./PaxHeaders/mapping-1.4.30000644000000000000000000000013215005124340012302 xustar0030 mtime=1746184416.326010819 30 atime=1746184416.655008822 30 ctime=1746184416.655008822 mapping-1.4.3/0000755000175000017500000000000015005124340012540 5ustar00philipphilipmapping-1.4.3/PaxHeaders/bootstrap0000644000000000000000000000007415005124246014174 xustar0030 atime=1746184416.351010667 30 ctime=1746184416.655008822 mapping-1.4.3/bootstrap0000755000175000017500000000025515005124246014512 0ustar00philipphilip#!/bin/bash ## Octave-Forge: mapping package bootstrap script ## Run this to generate the configure script set -e # halt if unhandled error cd src/ aclocal -Im4 autoconf mapping-1.4.3/PaxHeaders/inst0000644000000000000000000000013215005124340013122 xustar0030 mtime=1746184416.325010825 30 atime=1746184416.655008822 30 ctime=1746184416.655008822 mapping-1.4.3/inst/0000755000175000017500000000000015005124340013515 5ustar00philipphilipmapping-1.4.3/inst/PaxHeaders/km2deg.m0000644000000000000000000000006215005124246014535 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/km2deg.m0000644000175000017500000000420315005124246015050 0ustar00philipphilip## Copyright (C) 2008-2022 Alexander Barth ## Copyright (C) 2013-2022 Carnë Draug ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{deg} =} km2deg (@var{km}) ## @deftypefnx {Function File} {@var{deg} =} km2deg (@var{km}, @var{radius}) ## @deftypefnx {Function File} {@var{deg} =} km2deg (@var{km}, @var{sphere}) ## Convert distance to angle. ## ## Calculates the angles @var{deg} for the distances @var{km} in a sphere with ## @var{radius} (also in kilometers). If unspecified, radius defaults to 6371, ## the mean radius of Earth. ## ## Alternatively, @var{sphere} can be one of "sun", "mercury", "venus", "earth", ## "moon", "mars", "jupiter", "saturn", "uranus", "neptune", or "pluto", in ## which case radius will be set to that object mean radius. ## ## @seealso{deg2km, deg2sm, km2rad, km2deg, ## nm2deg, nm2rad, rad2km, rad2nm, rad2sm, sm2deg, sm2rad} ## @end deftypefn ## Author: Alexander Barth function deg = km2deg (km, radius = "earth") if (nargin < 1 || nargin > 2) print_usage(); elseif (ischar (radius)) ## Get radius of sphere with default units (km) radius = spheres_radius (radius); elseif (! isnumeric (radius) || ! isscalar (radius)) error ("km2deg: RADIUS must be a numeric scalar"); endif deg = 180 * km/(pi*radius); endfunction %!assert (deg2km (km2deg (10)), 10, 10*eps) %!assert (deg2km (km2deg (10, 80), 80), 10, 10*eps) %!assert (deg2km (km2deg (10, "pluto"), "pluto"), 10, 10*eps) mapping-1.4.3/inst/PaxHeaders/rasterdraw.m0000644000000000000000000000006215005124246015542 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/rasterdraw.m0000644000175000017500000001670415005124246016066 0ustar00philipphilip## Copyright (C) 2015-2022 Philip Nienhuis ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . ## -*- texinfo -*- ## @deftypefn {} {@var{h} =} rasterdraw (@var{data}) ## @deftypefnx {} {@var{h} =} rasterdraw (@var{data}, @var{rinfo}) ## @deftypefnx {} {@var{h} =} rasterdraw (@dots{}, @var{property}, @var{value}, @dots{}) ## Draw a GIS raster map. ## ## @var{data} can be a file name of a GIS raster data file, or a raster ## data struct made by rasterread; in the latter case input arg ## @var{rinfo}, a raster info struct also made by rasterread, is also ## required. ## ## Optionally, property/value pairs can be specified. Only the first ## four characters of the property need to be entered. The following ## property/value pairs are recognized: ## ## @itemize ## @item `bands': ## The value should be a scalar value or vector indicating which band(s) ## will be drawn in case of multi-band raster data. The default is all ## bands if the data contains three bands of integer data type, or the ## first band in all other cases. For non-integer raster data only one ## raster band can be specified. The number of bands must be 1 or 3. ## ## @item `colormap': ## The value should be a valid colormap to be used for indexed raster ## data. ## ## @item `missingvalue': ## A numerical value to substitute for missing values in the raster ## data. Default is NaN (for floating point raster data). ## @end itemize ## ## The optional output argument @var{h} is a graphics handle to the map. ## ## If the raster data to be plotted comprises just one band and a GDAL ## colortable, that colortable is converted to a colormap and used for ## drawing the map. The actual raster data are converted to uint8 if ## no missing data are present. ## ## Behind the scenes imshow() is invoked for the actual drawing for ## integer or single-band data, or pcolor() for floating point data with ## missing values. ## ## Note that drawing raster data can be quite slow for big data sets. ## Drawing maps larger than ~4000x4000 pixels is therefore not advised. ## ## @seealso{mapshow, rasterread, rasterinfo} ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2015-12-29 function [hr] = rasterdraw (varargin) if (nargin < 1) print_usage (); endif hr = -1; clrmap = []; misval = NaN; if (ischar (varargin{1})) ## Assume a raster file name. Just convey to rasterread.m fname = varargin{1}; [bands, rinfo] = rasterread (fname); nargin = nargin - 1; varargin(1) = []; elseif (isstruct (varargin{1})) ## Assume a raster struct made by rasterread.m. Checks: if (! isfield ("varargin(1)", "data") && ! ismatrix (varargin{1}(1).data)) error ("rasterdraw: unknown info raster struct setup"); else bands = varargin{1}; endif ## Check arg #2 - expecting info struct if (nargin < 2 || ! (isstruct (varargin{2}) && all (ismember ({"bbox", "projection", "height", "width", ... "geotransformation", "nbands"}, ... lower (fieldnames (varargin{2})))))) error ("rasterdraw: invalid or missing info struct (arg #2)"); else rinfo = varargin{2}; varargin(1:2) = []; nargin = nargin - 2; endif else ## Unknown "first" argument error ("rasterdraw: expecting filename or raster struct"); endif ibands = [1 : numel(bands)]; ## Optional propert/value arguments for ii=1:2:nargin if (nargin < ii+1) error ("rasterdraw: missing value for property %s", varargin{ii}); endif switch (lower (varargin{ii}(1:4))) case "band" ## Select raster band(s) to draw ibands = varargin{ii+1}; if (! isnumeric (ibands)) error ("rasterdraw: expecting numeric value(s) for 'bands' value"); elseif (any (ibands > numel (bands))) warning (["rasterdraw: data contains %d band(s), requested ", ... "band(s) [%s ] ignored.\n"], numel (bands), ... sprintf (" %d", ibands(find (ibands > numel (bands))))); ibands (find (ibands > numel (bands))) = []; endif if (! (numel (ibands) == 1 || numel (ibands) == 3)) error ("rasterdraw: either one or three bands must be selected.\n"); elseif (rinfo.BitDepth >= 32) ## Assume floating point data warning (["rasterdraw: floating point raster data. only band ", ... "%d will be drawn\n"], ibands(1)); endif case "colo" clrmap = varargin{ii+1}; if (! iscolormap (clrmap)) error ("rasterdraw: invalid colormap specified"); endif case "miss" misval = varargin{ii+1}; if (! isnumeric (misval)) error ("rasterdraw: numerical value expected for missing value"); endif otherwise warning ("rasterdraw: unknown or unimplemented property '%s' - skipped\n", ... varargin{ii}); endswitch endfor ## For each band process raster data, First band can be special ## FIXME Implement e.g., white ([1 1 1]) as default missing value for RGB ## multi-band images empdat = 0; ## 1. Treat & signal missing values (only for one-band maps) if (! isempty (bands(ibands(1)).ndv)) ndv = bands(ibands(1)).ndv; if (any (any (bands(1).data == bands(ibands(1)).ndv))) empdat = 1; bands(ibands(1)).data(find (bands(ibands(1)).data == ndv)) = misval; endif endif ## 2. If no missing data found & integer raster data type, cast to uint8 if (! empdat || rinfo.BitDepth <= 8) pic = uint8 (bands(ibands(1)).data); ## Band data no more used, clear - raster data can occupy awfully much RAM bands(ibands(1)).data = []; if (! isempty (bands(ibands(1)).colortable)) clrmap = bands(ibands(1)).colortable(:, 1:3); endif else pic = bands(ibands(1)).data; endif ## If no missing pixels, process next bands if present & requested if (numel (ibands) > 1 && ! empdat) ## Concat bands into picture pic(:, :, 1) = pic; for ii=2:numel (ibands) pic(:, :, ii) = uint8(bands(ibands(ii)).data); bands(ibands(1)).data = []; endfor endif ## Clear bands struct (also clears RAM for bands not requested) clear bands; ## Draw rasters using bbox values for axes limits if (empdat) bbox = rinfo.bbox; XX = [bbox(1, 1) : (diff (bbox(:, 1)) / (rinfo.Width)): bbox(2, 1)]; YY = [bbox(1, 2) : (diff (bbox(:, 2)) / (rinfo.Height)): bbox(2, 2)]; [nr, nc] = size (pic); hr = pcolor (XX, YY, [pic nan(nr, 1); nan(1, nc+1)]); ## Hide mesh: shading flat; else if (isempty (clrmap) || ! iscolormap (clrmap)) hr = imshow (pic, "xdata", rinfo.bbox(:, 1), "ydata", rinfo.bbox(:, 2)); else hr = imshow (pic, "xdata", rinfo.bbox(:, 1), "ydata", rinfo.bbox(:, 2), ... "colormap", clrmap); endif endif set (gca, "YDir", "normal"); axis equal; axis tight; endfunction mapping-1.4.3/inst/PaxHeaders/toDegrees.m0000644000000000000000000000006215005124246015305 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/toDegrees.m0000644000175000017500000000465015005124246015626 0ustar00philipphilip## Copyright (C) 2014-2022 Carnë Draug ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or (at ## your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{deg1}, @var{deg2}, @dots{}] =} toDegrees (@var{fromUnit}, @var{a1}, @var{a2}, @dots{}) ## Convert angles into degrees. ## ## Converts any number of input arguments, @var{a1}, @var{a2}, @dots{} ## with angles in @var{fromUnit}, into degrees. @var{fromUnit} may be ## @qcode{"radians"} or @qcode{"degrees"}. ## ## @example ## @group ## [deg1, deg2] = toDegrees ("radians", pi, [pi 2*pi]) ## @result {} ## [ 180 ] ## @result {} ## [ 180 360 ] ## @end group ## @end example ## ## @seealso{fromDegrees, fromRadians, rad2deg, toRadians, unitsratio} ## @end deftypefn ## Author: Carnë Draug function varargout = toDegrees (fromUnit, varargin) if (nargin < 1) print_usage (); endif valid_unit = validatestring (fromUnit, {"radians", "degrees"}, "toDegrees", "FROMUNIT"); switch (valid_unit(1)) case {"r"} varargout = cellfun (@rad2deg, varargin, "UniformOutput", false); case {"d"} varargout = varargin; endswitch endfunction %!test %! rad{1} = pi; %! rad{2} = [pi 2*pi]; %! rad{3} = [0 pi; 2*pi 0]; %! deg{1} = 180; %! deg{2} = [180 360]; %! deg{3} = [0 180; 360 0]; %! for i=1:3 %! assert (toDegrees ("degrees", deg{i}), deg{i}) %! assert (toDegrees ("radians", rad{i}), deg{i}) %! endfor %! %! ## test multiple angles same time %! assert (nthargout (1:3, @toDegrees, "radians", rad{:}), deg) %! assert (nthargout (1:2, @toDegrees, "radians", rad{:}), deg(1:2)) %! %! ## test abbreviations of degrees %! assert (nthargout (1:3, @toDegrees, "radian", rad{:}), deg) %! assert (nthargout (1:3, @toDegrees, "rad", rad{:}), deg) %! assert (nthargout (1:3, @toDegrees, "r", rad{:}), deg) %!error toRadians ("INVALID") mapping-1.4.3/inst/PaxHeaders/unitsratio.m0000644000000000000000000000006215005124246015565 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/unitsratio.m0000644000175000017500000004255015005124246016107 0ustar00philipphilip## Copyright (C) 2014-2022 Carnë Draug ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or (at ## your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} unitsratio (@var{to}, @var{from}) ## Return ratio for conversion between units. ## ## Returns the conversion ratio between two units, @var{to} and @var{from}, so ## that: ## ## @group ## @example ## unitsratio ("meter", "centimeter") ## @result{} ## 100 ## ## unitsratio ("inch", "foot") ## @result{} ## 12 ## @end example ## @end group ## ## This allows for easy conversion between units, for example: ## ## @group ## @example ## unitsratio ("mile", "km") * 156 ## @result{} ## 96.93391 ## @end example ## @end group ## ## For conversion between angle units, @qcode{"degrees"} and ## @qcode{"radians"} are supported. For conversion between length units, ## supports units defined in @code{validateLengthUnit}. ## ## @seealso{units, validateLengthUnit} ## @end deftypefn ## Author: Carnë Draug function ratio = unitsratio (to, from) if (nargin != 2) print_usage (); endif try valid_to = validatestring (to, {"radians", "degrees"}); valid_from = validatestring (from, {"radians", "degrees"}); catch valid_to = validateLengthUnit (to, "unitsratio", "TO"); valid_from = validateLengthUnit (from, "unitsratio", "FROM"); end_try_catch persistent ratios = struct ( ## angle units "degrees", struct ( "degrees", 1, "radians", pi / 180 ), "radians", struct ( "degrees", 180 / pi, "radians", 1 ), ## length units "meter", struct ( "meter", 1, "centimeter", 100, "millimeter", 1000, "micron", 10^6, "kilometer", 0.001, "nautical mile", 1 / 1852, "foot", 1 / 0.3048, "inch", 1 / 0.0254, "yard", 1 / 0.9144, "mile", 1 / 1609.344, "U.S. survey foot", 3937 / 1200, "U.S. survey mile (statute mile)", 3937 / (1200 * 5280), # 5280 survey foot "Clarke's foot", 1 / 0.3047972654, "German legal metre", 1 / 1.0000135965, "Indian foot", 1 / 0.3047996 ), ## same as meter times 0.01 "centimeter", struct ( "meter", 0.01, "centimeter", 0.01 * 100, "millimeter", 0.01 * 1000, "micron", 0.01 * 10^6, "kilometer", 0.01 * 0.001, "nautical mile", 0.01 / 1852, "foot", 0.01 / 0.3048, "inch", 0.01 / 0.0254, "yard", 0.01 / 0.9144, "mile", 0.01 / 1609.344, "U.S. survey foot", 0.01 * (3937 / 1200), "U.S. survey mile (statute mile)", 0.01 * 3937 / (1200 * 5280), "Clarke's foot", 0.01 / 0.3047972654, "German legal metre", 0.01 / 1.0000135965, "Indian foot", 0.01 / 0.3047996 ), ## same as meter times 0.001 "millimeter", struct ( "meter", 0.001, "centimeter", 0.001 * 100, "millimeter", 0.001 * 1000, "micron", 0.001 * 10^6, "kilometer", 0.001 * 0.001, "nautical mile", 0.001 / 1852, "foot", 0.001 / 0.3048, "inch", 0.001 / 0.0254, "yard", 0.001 / 0.9144, "mile", 0.001 / 1609.344, "U.S. survey foot", 0.001 * (3937 / 1200), "U.S. survey mile (statute mile)", 0.001 * 3937 / (1200 * 5280), "Clarke's foot", 0.001 / 0.3047972654, "German legal metre", 0.001 / 1.0000135965, "Indian foot", 0.001 / 0.3047996 ), ## same as meter times 10^-6 "micron", struct ( "meter", 10^-6, "centimeter", 10^-6 * 100, "millimeter", 10^-6 * 1000, "micron", 10^-6 * 10^6, "kilometer", 10^-6 * 0.001, "nautical mile", 10^-6 / 1852, "foot", 10^-6 / 0.3048, "inch", 10^-6 / 0.0254, "yard", 10^-6 / 0.9144, "mile", 10^-6 / 1609.344, "U.S. survey foot", 10^-6 * (3937 / 1200), "U.S. survey mile (statute mile)", 10^-6 * 3937 / (1200 * 5280), "Clarke's foot", 10^-6 / 0.3047972654, "German legal metre", 10^-6 / 1.0000135965, "Indian foot", 10^-6 / 0.3047996 ), ## same as meter times 1000 "kilometer", struct ( "meter", 1000, "centimeter", 1000 * 100, "millimeter", 1000 * 1000, "micron", 1000 * 1000000, "kilometer", 1000 * 0.001, "nautical mile", 1000 / 1852, "foot", 1000 / 0.3048, "inch", 1000 / 0.0254, "yard", 1000 / 0.9144, "mile", 1000 / 1609.344, "U.S. survey foot", 1000 * (3937 / 1200), "U.S. survey mile (statute mile)", 1000 * 3937 / (1200 * 5280), "Clarke's foot", 1000 / 0.3047972654, "German legal metre", 1000 / 1.0000135965, "Indian foot", 1000 / 0.3047996 ), ## exactly 1852 meters "nautical mile", struct ( "meter", 1852, "centimeter", 1852 * 100, "millimeter", 1852 * 1000, "micron", 1852 * 10^6, "kilometer", 1852 * 0.001, "nautical mile", 1, "foot", 2315000 / 381, # thank you wikipedia "inch", 27780000 / 381, "yard", 2315000 / 1143, # thank you wikipedia "mile", 1852 / 1609.344, # from how many meters are in a mile "U.S. survey foot", 1852 * 3937 / 1200, # from how many meters are in US survey foot "U.S. survey mile (statute mile)", 57875 / 50292, "Clarke's foot", 1852 / 0.3047972654, "German legal metre", 1852 / 1.0000135965, "Indian foot", 1852 / 0.3047996 # from how many meters are in an indian foot ), ## exactly 0.3048 meters. Also 12 inch "foot", struct ( "meter", 0.3048, "centimeter", 0.3048 * 100, "millimeter", 0.3048 * 1000, "micron", 0.3048 * 10^6, "kilometer", 0.3048 * 0.001, "nautical mile", 381 / 2315000, # inverse from nautical mile to foot "foot", 1, "inch", 12, "yard", 1 / 3, "mile", 1 / 5280, "U.S. survey foot", 0.3048 / (1200 / 3937), "U.S. survey mile (statute mile)", (5280 * 3977) / (0.3048 * 1200), "Clarke's foot", 0.3048 / 0.3047972654, "German legal metre", 0.3048 / 1.0000135965, "Indian foot", 0.3048 / 0.3047996 ), ## exactly 0.0254 meters "inch", struct ( "meter", 0.0254, "centimeter", 0.0254 * 100, "millimeter", 0.0254 * 1000, "micron", 0.0254 * 10^6, "kilometer", 0.0254 * 0.001, "nautical mile", 381 / 27780000, # inverse from nautical mile to inch "foot", 1 / 12, "inch", 1, "yard", 1 / 36, "mile", 1 / (5280 * 12), "U.S. survey foot", 0.0254 / (1200 / 3937), "U.S. survey mile (statute mile)", (5280 * 3977) / (0.0254 * 1200), "Clarke's foot", 0.0254 / 0.3047972654, "German legal metre", 0.0254 / 1.0000135965, "Indian foot", 0.0254 / 0.3047996 ), ## exactly 0.9144 meters. Also 3 feet "yard", struct ( "meter", 0.9144, "centimeter", 0.9144 * 100, "millimeter", 0.9144 * 1000, "micron", 0.9144 * 10^6, "kilometer", 0.9144 * 0.001, "nautical mile", 1143 / 2315000, # inverse from nautical mile to yard "foot", 3, "inch", 36, "yard", 1, "mile", 3 / 5280, "U.S. survey foot", 0.9144 / (1200 / 3937), "U.S. survey mile (statute mile)", (5280 * 3977) / (0.9144 * 1200), "Clarke's foot", 0.9144 / 0.3047972654, "German legal metre", 0.9144 / 1.0000135965, "Indian foot", 0.9144 / 0.3047996 ), ## exactly 1609.344 meters. Also 5280 feet "mile", struct ( "meter", 1609.344, "centimeter", 1609.344 * 100, "millimeter", 1609.344 * 1000, "micron", 1609.344 * 10^6, "kilometer", 1609.344 * 0.001, "nautical mile", 1609.344 / 1852, "foot", 5280, "inch", 5280 * 12, "yard", 5280 / 3, "mile", 1, "U.S. survey foot", 1609.344 / (1200 / 3937), "U.S. survey mile (statute mile)", (5280 * 3977) / (1609.344 * 1200), "Clarke's foot", 1609.344 / 0.3047972654, "German legal metre", 1609.344 / 1.0000135965, "Indian foot", 1609.344 / 0.3047996 ), ## exactly 1200 / 3937 "U.S. survey foot", struct ( "meter", 1200 / 3937, "centimeter", 100 * 1200 / 3937, "millimeter", 1000 * 1200 / 3937, "micron", 10^6 * 1200 / 3937, "kilometer", 0.001 * 1200 / 3937, "nautical mile", 1200 / (1852 * 3937), "foot", (1200 / 3937) / 0.3048, "inch", (1200 / 3937) / 0.0254, "yard", (1200 / 3937) / 0.9144, "mile", (1200 / 3937) / 1609.344, "U.S. survey foot", 1, "U.S. survey mile (statute mile)", 1 / 5280, "Clarke's foot", 1200 / (0.3047972654 * 3937), "German legal metre", 1200 / (1.0000135965 * 3937), "Indian foot", 1200 / (0.3047996 * 3937) ), ## the U.S. survey mile is 5280 survey feet (survey foot = 1200 / 3937 meters) "U.S. survey mile (statute mile)", struct ( "meter", 5280 * 1200 / 3937, "centimeter", 100 * 5280 * 1200 / 3937, "millimeter", 1000 * 5280 * 1200 / 3937, "micron", 10^6 * 5280 * 1200 / 3937, "kilometer", 0.001 * 5280 * 1200 / 3937, "nautical mile", 50292 / 57875, "foot", (0.3048 * 1200) / (5280 * 3977), "inch", (0.0254 * 1200) / (5280 * 3977), "yard", (0.9144 * 1200) / (5280 * 3977), "mile", (1609.344 * 1200) / (5280 * 3977), "U.S. survey foot", 5280, "U.S. survey mile (statute mile)", 1, "Clarke's foot", (5280 * 1200) / (0.3047972654 * 3937), "German legal metre", (5280 * 1200) / (1.0000135965 * 3937), "Indian foot", (5280 * 1200) / (0.3047996 * 3937) ), ## Defined as 0.3047972654 meters (from georepository.com) "Clarke's foot", struct ( "meter", 0.3047972654, "centimeter", 0.3047972654 * 100, "millimeter", 0.3047972654 * 1000, "micron", 0.3047972654 * 10^6, "kilometer", 0.3047972654 * 0.001, "nautical mile", 0.3047972654 / 1852, "foot", 0.3047972654 / 0.3048, "inch", 0.3047972654 / 0.0254, "yard", 0.3047972654 / 0.9144, "mile", 0.3047972654 / 1609.344, "U.S. survey foot", (0.3047972654 * 3937) / 1200, "U.S. survey mile (statute mile)", (0.3047972654 * 3937) / (5280 * 1200), "Clarke's foot", 1, "German legal metre", 0.3047972654 / 1.0000135965, "Indian foot", 0.3047972654 / 0.3047996 ), ## Defined as 1.0000135965 meters (longer than a meter by 13.5965 micrometers) "German legal metre", struct ( "meter", 1.0000135965, "centimeter", 1.0000135965 * 100, "millimeter", 1.0000135965 * 1000, "micron", 1.0000135965 * 10^6, "kilometer", 1.0000135965 * 0.001, "nautical mile", 1.0000135965 / 1852, "foot", 1.0000135965 / 0.3048, "inch", 1.0000135965 / 0.0254, "yard", 1.0000135965 / 0.9144, "mile", 1.0000135965 / 1609.344, "U.S. survey foot", (1.0000135965 * 3937) / 1200, "U.S. survey mile (statute mile)", (1.0000135965 * 3937) / (5280 * 1200), "Clarke's foot", 1.0000135965 / 0.3047972654, "German legal metre", 1, "Indian foot", 1.0000135965 / 0.3047996 ), ## The Indian survey foot is defined as exactly 0.3047996 m (wikipedia) "Indian foot", struct ( "meter", 0.3047996, "centimeter", 0.3047996 * 100, "millimeter", 0.3047996 * 1000, "micron", 0.3047996 * 10^6, "kilometer", 0.3047996 * 0.001, "nautical mile", 0.3047996 / 1852, "foot", 0.3047996 / 0.3048, "inch", 0.3047996 / 0.0254, "yard", 0.3047996 / 0.9144, "mile", 0.3047996 / 1609.344, "U.S. survey foot", (0.3047996 * 3937) / 1200, "U.S. survey mile (statute mile)", (0.3047996 * 3937) / (5280 * 1200), "Clarke's foot", 0.3047996 / 0.3047972654, "German legal metre", 0.3047996 / 1.0000135965, "Indian foot", 1 ) ); try ratio = ratios.(valid_from).(valid_to); catch error ("unitsratio: unknown conversion from %s to %s", from, to); end_try_catch endfunction %!assert (unitsratio ("inch", "foot"), 12) %!assert (unitsratio ("m", "cm"), 0.01) %!assert (unitsratio ("cm", "m"), 100) %!assert (unitsratio ("meter", "meter"), 1) %!assert (unitsratio ("degrees", "radians"), 180 / pi) %!assert (unitsratio ("radians", "degrees"), pi / 180) %!error unitsratio ("NOT A UNIT", "meter") %!error unitsratio ("meter", "NOT A UNIT") mapping-1.4.3/inst/PaxHeaders/rcurve.m0000644000000000000000000000006215005124246014672 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/rcurve.m0000644000175000017500000001210315005124246015203 0ustar00philipphilip## Copyright (C) 2018-2022 Philip Nienhuis ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or (at ## your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSEll. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{r} =} rcurve (@var{spheroid}, @var{lat}) ## @deftypefnx {Function File} {@var{r} =} rcurve (@var{type}, @var{spheroid}, @var{lat}) ## @deftypefnx {Function File} {@var{r} =} rcurve (@dots{}, @var{angleUnit}) ## Return the length of a curve based on its type: meridian, parallel, or ## transverse. ## ## Optional input argument @var{type} is one of "meridian", "parallel", or ## "transverse; default (when left empty or skipped) is "parallel". ## @var{spheroid} is the spheroid of choice (default: "wgs84"). @var{lat} ## is the latitude at which the curve length should be computed and can be ## a numeric scalar, vector or matrix. Output argument @var{r} will have the ## same size and dimension(s) as @var{lat}. ## ## Optional input argument @var{angleUnit} can be either "radians" or "degrees" ## (= default); just "r" or "d" will do. All character input is ## case-insensitive. ## ## Examples: ## ## @example ## r = rcurve ("parallel", "wgs84", 45) ## => r = ## 4.5176e+06 ## Note: this is in meters ## @end example ## ## @example ## r = rcurve ("", 45) ## => r = ## 4.5176e+06 ## @end example ## ## @example ## r = rcurve ("", "", 45) ## => r = ## 4.5176e+06 ## @end example ## ## @example ## r = rcurve ("", "", pi/4, "radians") ## => r = ## 4.5176e+06 ## @end example ## ## @example ## r = rcurve ("meridian", "wgs84", 45) ## => r = ## 6.3674e+06 ## @end example ## ## @example ## r = rcurve ("transverse", "wgs84", 45) ## => r = ## 6.3888e+06 ## @end example ## ## Also can use structures as inputs: ## @example ## r = rcurve("", referenceEllipsoid ("venus"), 45) ## => r = ## 4.2793e+06 ## @end example ## @end deftypefn ## Function supplied by anonymous contributor, see: ## https://savannah.gnu.org/patch/index.php?9658 function r = rcurve (varargin) if (nargin < 2 || nargin > 4) print_usage (); elseif (nargin == 2) ## Neither type nor angleUnit specified type = "parallel"; angleUnit = "degrees"; spheroid = varargin{1}; lat = varargin{2}; ip = 1; elseif (nargin >= 3) if (isnumeric (varargin{2}) && isreal (varargin{2})) ## arg{1} = spheroid, type skipped type = "parallel"; ip = 1; elseif (isnumeric (varargin{3}) && isreal (varargin{3})) ## arg{1} = type, no angleunit given angleUnit = "degrees"; ip = 0; else error ("rcurve: real numeric input expected for Lat"); endif type = varargin{ip + 1}; spheroid = varargin{ip + 2}; lat = varargin{ip + 3}; endif if (nargin == 4) if (ischar (varargin{4})) angleUnit = varargin{4}; else error ("rcurve: 'degrees' or 'radians' expected for angleUnits"); endif endif if isempty (type) type = "parallel"; endif if (isnumeric (spheroid)) spheroid = num2str (spheroid); endif E = sph_chk (spheroid); if (! ischar (angleUnit) || ! ismember (lower (angleUnit(1)), {"d", "r"})) error ("rcurve: angleUnit should be one of 'degrees' or 'radians'") endif if (strncmpi (lower (angleUnit), "r", 1) == 1) c_l = cos (lat); s_l = sin (lat); else c_l = cosd (lat); s_l = sind (lat); endif ## Insight From: Algorithms for Global Positioning pg 370-372 e2 = E.Eccentricity ^ 2; R = E.SemimajorAxis; e_p = e2 / (1 - e2); N = (R * sqrt ( 1 + e_p) ./ (sqrt (1 + e_p * c_l .^ 2))); switch type case {"meridian"} w = sqrt (1 - e2 .* s_l .^ 2); r = R * (1 - e2 ) ./ (w .^ 3); case {"parallel"} r = N .* c_l; case {"transverse"} r = N; otherwise error ("rcurve: type should be one of 'meridian', 'parallel', or 'transverse'") endswitch endfunction %!test %! assert (rcurve ("", 45), 4517590.87885, 10e-6) %% Row vector %!test %! assert (rcurve ("", [45; 20]), [4517590.87885; 5995836.38390], 10e-6) %% Column vector %!test %! assert (rcurve ("", [45, 20]), [4517590.87885, 5995836.38390], 10e-6) %% Matrix %!test %! assert (rcurve ("", [60 45; 35 20]), [3197104.58692, 4517590.87885; 5230426.84020, 5995836.38390], 10e-6) %!test %! assert (rcurve ("", "", 45), 4517590.87885, 10e-6) %!test %! assert (rcurve ("transverse", "", 45), 6388838.29012, 10e-6) %!test %! assert (rcurve ("meridian", "", 45), 6367381.81562, 10e-6) %!error rcurve ("","", 45, "km") %!error rcurve ("", "", "A") %!error rcurve ("", "", 45i) %!error rcurve ('All', "", 45) mapping-1.4.3/inst/PaxHeaders/dms2degrees.m0000644000000000000000000000006215005124246015570 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/dms2degrees.m0000644000175000017500000000671615005124246016116 0ustar00philipphilip## Copyright (C) 2014-2022 Carnë Draug ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or (at ## your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} dms2degrees (@var{dms}) ## Convert degrees, and minutes components into decimal degrees. ## ## @var{dms} must be a 3 column matrix with one row per angle, and each ## column correspoding to its degrees (an integer), minutes (a less than ## 60 integer, and seconds (a less than 60 value, possibly fractional) ## components. ## ## The sign of the angle must be defined on its first non-zero component only, ## i.e., if an angle is negative, the seconds component must be positive ## unless both minutes and degrees are zero, and the minutes component ## must be positive unless the degrees component is zero. ## ## @seealso{degrees2dm, degree2dms, dm2degrees} ## @end deftypefn ## Author: Carnë Draug function deg = dms2degrees (dms) if (nargin != 1) print_usage (); elseif (! isnumeric (dms) || ndims (dms) != 2 || columns (dms) != 3) error ("dms2degrees: DMS must be a numeric matrix with 3 columns"); elseif (any (fix (dms(:,1)) != dms(:,1))) error ("dms2degrees: degrees component (first column) must be an integer"); elseif (any (dms(:,2) >= 60)) error ("dms2degrees: minutes component (second column) must be less than 60"); elseif (any (dms(:,3) >= 60)) error ("dms2degrees: seconds component (third column) must be less than 60"); endif ## join the degrees and minutes parts adms = abs (dms); deg = sum ([adms(:,1) adms(:,2)/60 adms(:,3)/3600], 2); ## change the sign if any part is negative and check that negative ## sign is present on the first non-zero part only negs = dms < 0; nnz_d = dms(:,1) != 0; nnz_m = dms(:,2) != 0; if (any ((nnz_d | nnz_m) & negs(:,3))) error ("dms2degrees: second must be positive if degree or minute is non-zero"); elseif (any (nnz_d & negs(:,2))) error ("dms2degrees: minute must be positive if degree is non-zero"); endif deg(any (negs, 2)) *= -1; endfunction %!test %! hs = 0.5/60; %! deg = [ 10 10.5 -10.5 -10 -0.5 0.5 hs 0 -1/60 ]' + hs; %! dms = [ 10 0 30 %! 10 30 30 %! -10 29 30 %! -9 59 30 %! 0 -29 30 %! 0 30 30 %! 0 1 0 %! 0 0 30 %! 0 0 -30]; %! for i = 1:rows (dms) %! assert (dms2degrees (dms(i,:)), deg(i), 2*10^-15); %! endfor %! assert (dms2degrees (dms), deg, eps*10); %! assert (dms2degrees (single (dms)), single (deg), 3*10^-8); %!error dms2degrees ([5 40 60]) %!error dms2degrees ([5 40 61]) %!error <3 columns> dms2degrees ([5 50]) %!error dms2degrees ([5 -40 9]) %!error dms2degrees ([-5 -40 9]) %!error dms2degrees ([0 -40 -9]) %!error <3 columns> dms2degrees (rand (7, 3, 3)) mapping-1.4.3/inst/PaxHeaders/aer2ned.m0000644000000000000000000000006215005124246014704 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/aer2ned.m0000644000175000017500000001070315005124246015221 0ustar00philipphilip## Copyright (c) 2014-2022 Michael Hirsch, Ph.D. ## Copyright (c) 2013-2022, Felipe Geremia Nievinski ## Copyright (C) 2019-2022 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{n}, @var{e}, @var{d} =} aer2ned (@var{az}, @var{el}, @var{slantrange}) ## @deftypefnx {Function File} {@var{n}, @var{e}, @var{d} =} aer2ned (@var{az}, @var{el}, @var{slantrange}, @var{angleUnit}) ## Convert Azimuth, Elevation and Range (AER) coordinates to North, East, Down ## (NED) coordinates. ## ## Inputs: ## @itemize ## @item ## @var{az}, @var{el}, @var{slantrange}: look angles and distance to target ## point (ange, angle, length). Scalars, vectors and nD-arrays are accepted ## and should have the same dimensions and length units. ## ## @item ## @var{angleUnit}: string for angular units ('degrees' or 'radians', ## case-insensitive, just the first character will do). Default is 'degrees'. ## @end itemize ## ## Outputs: ## @itemize ## @item ## @var{n}, @var{e}, @var{d}: North, East, Down coordinates of points. ## (same length units as inputs). ## @end itemize ## ## Examples: ## @example ## [n, e, d] = aer2ned (33, 70, 1e3) ## n = 286.84 ## e = 186.28 ## d = -939.69 ## @end example ## ## With radians ## @example ## [n, e, d] = aer2ned (pi/4, pi/3,1e3, "radians") ## n = 353.55 ## e = 353.55 ## d = -866.03 ## @end example ## ## @seealso{ned2aer, aer2ecef, aer2enu, aer2geodetic} ## ## @end deftypefn ## Function adapted by anonymous contributor, see: ## https://savannah.gnu.org/patch/index.php?8377 function [n, e, d] = aer2ned (az, el, slantrange, angleUnit = "degrees") if (nargin < 3) print_usage(); endif if (! isnumeric (az) || ! isreal (az) || ... ! isnumeric (el) || ! isreal (el) || ... ! isnumeric (slantrange) || ! isreal (slantrange)) error ("aer2ned: numeric values expected for first three inputs."); endif if (! all (size (az) == size (el)) || ! all (size (el) == size (slantrange))) error ("aer2ned: non-matching dimensions of inputs."); endif if (! ischar (angleUnit)) error ("aer2ned: character value expected for 'angleUnit'"); elseif (strncmpi (angleUnit, "degrees", length (angleUnit))) az = deg2rad (az); el = deg2rad (el); elseif (! strncmpi (angleUnit, "radians", length (angleUnit))) error ("aer2ned: illegal input for 'angleUnit'"); endif ## Calculation of AER2NED d = -slantrange .* sin (el); r = slantrange .* cos (el); e = r .* sin (az); n = r .* cos (az); endfunction %!test %! [n, e, d] = aer2ned (33, 70, 1e3); %! assert ([n, e, d], [286.84222, 186.277521, -939.69262], 10e-6) %! [e, n, u] = aer2ned (0.57595865, 1.221730476, 1e3, "rad"); %! assert ([e, n, u], [286.84222, 186.277521, -939.69262], 10e-6) %!error aer2ned("s", 25, 1e3) %!error aer2ned(3i, 25, 1e3) %!error aer2ned(33, "s", 1e3) %!error aer2ned(33, 3i, 1e3) %!error aer2ned(33, 25, "s") %!error aer2ned(33, 25, 3i) %!error aer2ned ([1 1], [2 2]', [4 5]) %!error aer2ned ([1 1], [2 2], [4 5 6]) %!error aer2ned (1, 2, 3, 4); %!error aer2ned (33, 70, 1e3, "f"); %!error aer2ned (33, 70, 1e3, "degreef"); mapping-1.4.3/inst/PaxHeaders/shaperead.m0000644000000000000000000000006215005124246015320 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/shaperead.m0000644000175000017500000011622515005124246015643 0ustar00philipphilip## Copyright (C) 2014-2022 Philip Nienhuis ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} [@var{outstruct} ] = shaperead (@var{shp_filename}) ## @deftypefnx {Function File} [@var{outstruct} ] = shaperead (@var{shp_filename}, @var{outstyle}) ## @deftypefnx {Function File} [@var{outstruct} ] = shaperead (@var{shp_filename}, @var{outstyle}, @var{opts}) ## @deftypefnx {Function File} [@var{outstruct}, @var{atts} ] = shaperead (@var{shp_filename}, ...) ## Read an ArcGis shapefile set (shp, shx and dbf). ## ## Depending on the value of @var{outstyle} some different output formats ## will be returned: ## ## @table @code ## @item 0 (numeric) ## @itemx ml (case-insensitive) ## @itemx m ## Return a Matlab-compatible M X 1 struct with a separate entry for each shape ## feature in the shape file. Each struct element contains fields "Geometry" ## (shape type), "BoundingBox" ([minX minY ; maxX maxY]), X, Y (coordinates of ## points in the shape item as row vectors). For multi-part items, the ## coordinates of each part are separated by NaNs. This output format supports ## neither M and Z type nor MultiPatch shape features. For M and Z type shape ## features the M and Z values will simply be ignored. ## The struct is augmented with attributes found in the accompanying .dbf file, ## if found. ## ## For ML-style output, if only one output argument is requested the attributes ## in the .dbf file will be augmented to that struct. If two output arguments ## are requested, the attributes will be returned separately in output struct ## @var{atts}. ## ## @item 1 (numeric) ## @itemx ext (case-insensitive) ## @itemx e ## Same as 1 but M and Z type and MultiPatch shape features are accepted. The ## resulting output struct is no more ML-compatible. If the shapefile contains ## M and/or Z type shape features the mapstruct or geostruct has extra fields M ## and -optionally- Z. Note that MultiPatch shape features may not have ## M-values even if Z-values are present. For MultiPatch shapes another field ## Parts is added, a Px2 array with zero-based indices to the first vertex of ## each subfeature in the XYZ fields in column 1 and the type of each ## subfeature in column 2; P is the number of shape feature parts. ## ## @item 2 (numeric) ## @itemx oct (case-insensitive) ## @itemx o ## Return a struct containing a N X 6 double array "vals" containing the X, Y, ## and Z coordinates, M-values, record nr. and type of each point in the shape ## file. If no M or Z values were present the relevant columns contain ## NaNs. Individual shape features and shape parts are separated by a row of ## NaN values. The field "idx" contains 1-based pointers into field vals to ## the first vertex of each shape feature. ## Field "bbox" contains an 8 X M double array of XYZ coordinates of the ## bounding boxes and min/max M-values corresponding to the M items found in ## the .shp file; for point shapes these contain NaNs. ## Field "npt" contains a 1 X M array of the number of points for each item. ## Field "npr" contains a 1 X M cell array containing a row of P part indices ## (zero-based) for each Polyline, Polygon or MultiPatch part in the shape ## file; for multipatch each cell contains another row with the part types; ## for other item types (point etc.) the cell array contains empty rows. ## A separate field "shpbox" contains the overall bounding box X, Y and Z ## coordinates and min/max M-values in a 4 X 2 double array. If the shape file ## contains no Z or M values the corresponding columns are filled with NaNs. ## ## The struct field "fields" contains a cellstr array with names of the columns. ## If a corresponding .dbf file was read, the struct array also contains ## a field for each attribute found in the .dbf file with the corresponding ## field name, each containing a 1 X M array of attribute values matching the ## M items in the .shp file. These arrays can be double, char or logical, ## depending on the type found in the .dbf file. ## ## @item 3 (numeric) ## @itemx dat (case-insensitive) ## @itemx d ## Same as OCT or 0 but without a row of NaN values between each shape ## file item in the VALS array. ## @end table ## ## If a character option is given, just one character will suffice. The default ## for @var{outstyle} is "ml". ## ## The output of 'shaperead' can be influenced by property-value pairs. The ## following properties are recognized (of which only the first three ## characters are significant, case doesn't matter): ## ## @table @code ## @item Attributes ## Normally all attributes associated with the shape features will be read ## and returned in the output struct(s). To limit this to just some ## attributes, enter a value consisting of a cell array of attribute names to ## be read. To have no attributes read at all, specify @{@}, an empty cell ## array. @* ## Attributes "Geometry", "BoundingBox", "X", "Y", "Lat", and "Lon" are ## contained within the .shp file and will be returned in any case. If ## specified these values will be ignored. In the unlikely case that the ## associated .dbf file also contains these attributes (truncated to 10 ## characters) they will be prepended with an underscore (@code {_}). ## ## @item BoundingBox ## Select only those shape items (features) whose bounding box lies within, or ## intersects in at least one point with the limits of the BoundingBox value (a ## 2 X 2 double array [Minx, MinY; MaxX, MaxY]). ## No intersection or clipping with the BoundingBox value will be done by ## default! ## ## @item Clip ## (only useful in conjuction with the BoundingBox property) If a value of 1 ## or true is supplied, clip all shapes to the bounding box limits. This ## option may take quite a bit of processing time. If a value of "0" or false ## is given, do not perform clipping. The default value is 0. ## Clipping is merely meant to be performed in the XY plane. Clipping 3D ## shapes is supported but may lead to unexpected results. ## For Z and M type polylines and polygons including MultiPatch and ## Longitude/Latitude/Height types, Z (Height) and M values for each vertex in ## the clipped shape feature are simply copied over from the nearest vertex in ## the original shape feature. This implies that Z and M values of new ## vertices created on the bounding box edges may be less optimal. ## ## For clipping polylines and polygons the Octave-Forge geometry package needs ## to be installed and loaded. ## ## @item Debug ## If a value of 'true' or 1 is given, shaperead echoes the current record ## number while reading. Can be useful for very big shapefiles. The default ## value is 0 (no feedback). If a Matlab-compatible output structarray is ## requested and the Bounding Box property is specified, the extracted shape ## feature indices are added to the field "___Shape_feature_nr___". ## ## @item RecordNumbers ## Select only those records whose numbers are listed as integer values in ## an array following RecordNumbers property. Neither the size nor the class of ## the array matters as long as it is a numeric array. ## ## @item UseGeoCoords ## (Only applicable if a Matlab-style output struct is requested). If a value ## of 'true' (or 1) is supplied, return a geostruct rather than a mapstruct. ## If a value of 0 or false is given, return a mapstruct. ## The mere difference is that in a geostruct the fields 'X' and 'Y' (and ## optionally 'Z') are replaced by 'Long' and 'Lat' (and 'Hght'). The ## default value is 'false' (return a mapstruct'). ## @end table ## ## Ref: http://www.esri.com/library/whitepapers/pdfs/shapefile.pdf ## ## @seealso{geoshow, mapshow, shapedraw, shapeinfo} ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2014-11-07 function [ outs, oatt ] = shaperead (fname, varargin); ## FIXME Implementation needed of these ML input arguments: ## - Selector (supposedly difficult. I'd prefer myself to leave this ## outside of shaperead, it needlessly complicates and slows ## this function /PRN) ## Check input if (nargin < 1) print_usage (); endif ## Check file name [pth, fnm, ext] = fileparts (fname); if (isempty (ext)) bname = fname; fname = [fname ".shp"]; elseif (isempty (pth)) ## Later on bname.shx and bname.dbf will be read bname = fnm; else ## Later on bname.shx and bname.dbf will be read bname = [pth filesep fnm]; endif ## Find out what args have been supplied if (nargin == 1) ## Only filename supplied. Set "ml" (Matlab) type as default outopts = 0; elseif (nargin == 2) ## Assume filename + outopts was supplied if (isempty (varargin{1})) ## Assume ML-style output outopts = 0; else outopts = varargin{1}; endif varargin = {}; elseif (rem (nargin, 2) == 0) ## Even number of input args => Outopts & at least one pair of varargin outopts = varargin{1}; varargin(1) = []; else ## Odd nr; maybe only filename and prop/val(s) supplied, outstyle skipped if (ischar (varargin{1})) ## Check arg#2, must be a property name then if (! ismember (lower (varargin{1}(1:min(3, numel (varargin{1})))), ... {"att", "bou", "cli", "deb", "rec", "sel", "use"})) error ("shaperead: property name expected for arg. #2"); endif else ## no outstyle or property => wrong input print_usage (); endif outopts = 0; endif ## Check output type arg if (isnumeric (outopts)) if (outopts < 0 || outopts > 3) error ("shaperead: arg. #2 integer value out of range 0-3\n"); endif elseif (ischar (outopts)) outopts = lower (outopts); if (! any (strncmp (outopts, {"ml", "ext", "oct", "dat"}, 1))) error (["shaperead: arg. #2 char value should be one of 'ml', 'ext', ", ... "'oct' or 'dat'\n"]); endif switch outopts case {"ml", "m"} outopts = 0; case {"ext", "e"} outopts = 1; case {"oct", "o"} outopts = 2; case {"dat", "d"} outopts = 3; otherwise error (["shaperead: illegal value for arg. #2: '%s' - expected ", ... "'ml', 'ext', 'oct' of 'dat'"], outopts); endswitch else error ("shaperead: numeric or character type expected for arg. #2\n"); endif ## Check .shp file existence fidp = fopen (fname, "r"); ## Postpone file opening error until after other provisional input validation if (fidp > 0) ## Temporarily close to avoid file handle leaks during further input checks fclose (fidp); endif ## - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ## Open .shx file to help speed up seeks to next records. We need this info ## for s_recs check below have_shx = 0; fidx = fopen ([bname ".shx"], "r"); if (fidx < 0) s_recs = []; else fseek (fidx, 24, "bof"); fxlng = fread (fidx, 1, "int32", 72, "ieee-be"); nrec = (fxlng - 50) / 4; fseek (fidx, 100, "bof"); ## Get record start positions & -lengths in 16-bit words ridx = reshape (fread (fidx, nrec*2, "int32", 0, "ieee-be"), 2, [])'; fclose (fidx); ## Get indices & lengths in bytes ridx *= 2; have_shx = 1; s_recs = [1 : size(ridx, 1)]; endif ## Parse options; first set defaults clip = 0; dbug = 0; s_atts = []; s_bbox = []; s_geo = 0; ## Init collection of records that meet BB criteria bb_union = []; ## Process input args for ii = 1:2:length (varargin) if (! ischar (varargin{ii})) error ("shaperead: property %d: property name expected but got a %s value", ... (ii+1)/2, class (varargin{ii})); elseif (numel (varargin{ii}) < 3) warning ("shaperead: unknown option '%s' - ignored\n", varargin{ii}); else switch (lower (varargin{ii})(1:3)) case "att" ## Select records based on attribute values s_atts = varargin{ii+1}; ## Weed out .shp file attributes s_atts = setdiff (s_atts, {"Geometry", "BoundingBox", ... "X", "Y", "Lat", "Lon"}); case "bou" ## Select whether record/shape features partly lie inside or outside limits try s_bbox = double (varargin{ii+1}); if (numel (s_bbox) != 4) error ("shaperead: 2 X 2 numeric array expected for BoundingBox\n"); endif catch error ("shaperead: numeric 2 X 2 array expected for BoundingBox\n"); end_try_catch ## Initialize supplementary polygon array here sbox = [s_bbox(1) s_bbox(3); s_bbox(2) s_bbox(3); s_bbox(2) s_bbox(4); ... s_bbox(1) s_bbox(4); s_bbox(1) s_bbox(3)]; case "cli" ## Clip polygons to requested BoundingBox try clip = logical (varargin{ii+1}); catch error ("numeric or logical value expected for 'Clip'\n"); end_try_catch case "deb" ## Set verbose output (count records) try dbug = logical (varargin{ii+1}); catch error ("numeric or logical value expected for 'Debug'\n"); end_try_catch case "rec" ## Select record nrs directly. Check for proper type & clean up try s_recs = sort (unique (double (varargin{ii+1}(:)))); if (have_shx && any (s_recs > nrec)) printf (["shaperead: requested record nos. > nr. of records ", ... "(%d) ignored\n"], nrec); s_recs (find (srecs > nrec)) = []; endif catch error ("shaperead: numeric value or array expected for RecordNumbers\n"); end_try_catch case "sel" ## A hard one, to be implemented later? printf ("shaperead: 'Selector' option not implemented, option ignored\n"); case "use" ## Return a geostruct or a mapstruct (default). Only for ML-structs if (outopts != 0) error ("shaperead: UseGeoCoords only valid for Matlab-style output\n"); endif try s_geo = logical (varargin{ii+1}); catch error ("shaperead: logical value type expected for 'UseGeoCoords'\n"); end_try_catch otherwise warning ("shaperead: unknown option '%s' - ignored\n", varargin{ii}); endswitch endif endfor ## Post-processing if (clip) if (isempty (s_bbox)) warning ("shaperead: no BoundingBox supplied => Clip option ignored.\n"); clip = 0; endif if (isempty (which ("clipPolygon_clipper"))) ## No OF geometry package? printf ("shaperead: function 'clipPolygon' not found. Clip option ignored\n"); warning (" (OF geometry package installed and loaded?)\n"); clip = 0; endif if (isempty (which ("distancePoints"))) ## No OF geometry package? printf ("shaperead: function 'distancePoints' not found. Clip option ignored\n"); warning (" (OF geometry package installed and loaded?)\n"); clip = 0; endif endif if (fidp < 0) ## Only now convey file open error message error ("shaperead: can't open file %s\n", fname); else ## Open .shp file fidp = fopen (fname, "r"); endif if (fidx < 0) warning ("shaperead: index file %s not found\n", [fnm ".shx"]); endif ## ============= Preparations done, now we can start reading ============ ## ---------------------- 2. Read .shp file proper ---------------------- ## Start reading header fseek (fidp, 0, "bof"); ## Read & check file code fcode = fread (fidp, 1, "int32", 20, "ieee-be"); if (fcode != 9994) error ("%s is not a valid shapefile\n", fname); endif flngt = fread (fidp, 1, "int32", 0, "ieee-be") * 2; fvsn = fread (fidp, 1, "int32", 0, "ieee-le"); shpt = fread (fidp, 1, "int32"); ## Shape file type shpbox.X(1) = fread (fidp, 1, "double"); shpbox.Y(1) = fread (fidp, 1, "double"); shpbox.X(2) = fread (fidp, 1, "double"); shpbox.Y(2) = fread (fidp, 1, "double"); shpbox.Z(1) = fread (fidp, 1, "double"); shpbox.Z(2) = fread (fidp, 1, "double"); shpbox.M(1) = fread (fidp, 1, "double"); shpbox.M(2) = fread (fidp, 1, "double"); ## FIXME: scan shp file in advance to assess nr of XY points, to be able to ## preallocate rec array. May be difficult, .shp is not favorable for ## it. Initial tries showed no significant speed advantage yet over ## the incremental allocation scheme implemented in Ls. 611+ & 631+ ## for oct/plt style output. For ml-style it is much harder as ## we'd need to preallocate a potentially very heterogeneous struct ## array. ## Prepare for unsupported (in ML output) shape types unsupp = 0; ## Echo warning if dbug was set ign_mz = (outopts == 0) && dbug; ## Buffer for record data BUFSIZE = 10000; ## Read records, 1 by 1. Initialize final array vals = npt = npr = bbox = idx = nullsh = []; ## Init nr. of shapes read nshp = 0; ## Temp pointer to keep track of array size and increase it w. BUFSIZE rows ivals = 1; ## Provisionally assume file has M (measure) values has_M = true; ## Record index number (equals struct element number) ir = 1; ## Init output struct outs = repmat (struct ("Geometry", ""), 0, 1); do ## If the .shx file is there, skip directly to requested record if (have_shx) fseek (fidp, ridx(s_recs(ir), 1), "bof"); endif if (dbug) printf ("Reading record %d ...\r", ir); endif val = NaN(1, 6); ## Read record index number & record length val(5) = fread (fidp, 1, "int32", 0, "ieee-be"); rlen = fread (fidp, 1, "int32", 0, "ieee-be"); ## Here we decide if the record need be read at all, based on s_recs if (isempty (s_recs) || ismember (double (val(5)), s_recs)) ## => this record # has been desired; proceed. Read shape feature type val(6) = fread (fidp, 1, "int32"); rincl = 1; ## see s_bbox, below ## Init values for this shape item tbbox = NaN(1, 8); switch val(6) case 1 ## Point val(1:2) = fread (fidp, 2, "double"); val(3:4) = NaN; tnpt = 1; tnpr = 0; case 11 ## PointZ val(1:4) = fread (fidp, 4, "double"); tnpt = 1; tnpr = 0; case 21 ## PointM val(1:2) = fread (fidp, 2, "double"); ## "Z" val(3) = 0; ## M val(4) = fread (fidp, 1, "double"); tnpt = 1; tnpr = 0; case 8 ## Multipoint ## Read bounding box tbbox(1:4) = fread (fidp, 4, "double"); tnpt = fread (fidp, 1, "int32"); val(1:tnpt, 1:2) = reshape (fread (fidp, tnpt*2, "double"), 2, [])'; val(1:tnpt, 3:4) = NaN; ## Copy rec index & type down val(2:tnpt, 5:6) = repmat (val(1, 5:6), tnpt-1, 1); tnpr = 0; case 18 ## MultipointZ tbbox(1:4) = fread (fidp, 4, "double"); tnpt = fread (fidp, 1, "int32"); val(1:tnpt, 1:2) = reshape (fread (fidp, tnpt*2, "double"), 2, [])'; ## Z min & max values tbbox(5:6) = fread (fidp, 2, "double"); ## Augment val array with Z values val(1:tnpt, 3) = fread(fidp, tnpt, "double")'; ## M min & max values tbbox(7:8) = fread (fidp, 2, "double"); if (val(1, 5) == 1) has_M = checkM (fidp, val(1, 6), shpbox); endif if (has_M) ## Augment val array with M values val(1:tnpt, 4) = fread(fidp, tnpt, "double")'; ## Copy rec index & type down val(2:tnpt, 5:6) = repmat (val(1, 5:6), tnpt-1, 1); tnpr = 0; endif case 28 ## MultipointM tbbox(1:4) = fread (fidp, 4, "double"); tnpt = fread (fidp, 1, "int32"); val(1:tnpt, 1:2) = reshape (fread (fidp, tnpt*2, "double"), 2, [])'; ## Insert empty column for Z val(1:tnpt, 3:4) = NaN; if (val(1, 5) == 1) has_M = checkM (fidp, val(1, 6), shpbox); endif if (has_M) ## M min & max values tbbox(7:8) = fread (fidp, 2, "double"); ## Augment val array with M values val(1:tnpt, 4) = fread(fidp, tnpt, "double")'; endif ## Copy rec index & type down val(2:tnpt, 5:6) = repmat (val(1, 5:6), tnpt-1, 1); tnpr = 0; case {3, 5} ## Polyline/-gon tbbox(1:4) = fread (fidp, 4, "double"); ## Read nparts, npoints, nparts pointers nparts = fread (fidp, 1, "int32"); tnpt = fread (fidp, 1, "int32"); tnpr = fread (fidp, nparts, "int32")'; ## Read XY point coordinates val(1:tnpt, 1:2) = reshape (fread (fidp, tnpt*2, "double"), 2, [])'; ## No Z or M data val(1:tnpt, 3:4) = NaN; ## Copy rec index and type down val(2:tnpt, 5:6) = repmat (val(1, 5:6), tnpt-1, 1); case {13, 15} ## Polyline/-gonZ tbbox(1:4) = fread (fidp, 4, "double"); ## Read nparts, npoints, nparts pointers nparts = fread (fidp, 1, "int32"); tnpt = fread (fidp, 1, "int32"); tnpr = fread (fidp, nparts, "int32")'; ## Read XY point coordinates val(1:tnpt, 1:2) = reshape (fread (fidp, tnpt*2, "double"), 2, [])'; ## Z min & max values + data tbbox(5:6) = fread (fidp, 2, "double"); val(1:tnpt, 3) = fread(fidp, tnpt, "double")'; if (val(1, 5) == 1) has_M = checkM (fidp, val(1, 6), shpbox); endif if (has_M) ## M min & max values + data tbbox(7:8) = fread (fidp, 2, "double"); val(1:tnpt, 4) = fread(fidp, tnpt, "double")'; ## Copy rec index and type down val(2:tnpt, 5:6) = repmat (val(1, 5:6), tnpt-1, 1); endif case {23, 25} ## Polyline/-gonM tbbox(1:4) = fread (fidp, 4, "double"); ## Read nparts, npoints, nparts pointers nparts = fread (fidp, 1, "int32"); tnpt = fread (fidp, 1, "int32"); tnpr = fread (fidp, nparts, "int32")'; ## Read XY point coordinates val(1:tnpt, 1:2) = reshape (fread (fidp, tnpt*2, "double"), 2, [])'; ## No Z data val(1:tnpt, 3) = NaN; if (val(1, 5) == 1) has_M = checkM (fidp, val(1, 6), shpbox); endif if (has_M) ## M min & max values + data tbbox(7:8) = fread (fidp, 2, "double"); val(1:tnpt, 4) = fread(fidp, tnpt, "double")'; ## Copy rec index and type down val(2:tnpt, 5:6) = repmat (val(1, 5:6), tnpt-1, 1); endif case 31 ## Multipatch tbbox(1:4) = fread (fidp, 4, "double"); ## Read nparts, npoints, nparts pointers, npart types nparts = fread (fidp, 1, "int32"); tnpt = fread (fidp, 1, "int32"); ## Npart types is just another row under npart pointers => read both. ## Provisionally transpose, this is later on reset after NaN insertion tnpr = reshape (fread (fidp, nparts*2, "int32")', [], 2)'; ## Read XY point coordinates val(1:tnpt, 1:2) = reshape (fread (fidp, tnpt*2, "double"), 2, [])'; ## Z min & max values + data. Watch out for incomplete .shp file EOF = (ftell (fidp) > flngt-2); if (! EOF) tbbox(5:6) = fread (fidp, 2, "double"); val(1:tnpt, 3) = fread(fidp, tnpt, "double")'; endif fptr = ftell (fidp); EOF = (fptr > flngt-2); if (! EOF && has_M) has_M = checkM (fidp, val(1, 6), shpbox); endif ## M min & max values + data. Watch out for incomplete .shp file if (! EOF && has_M) tbbox(7:8) = fread (fidp, 2, "double"); val(1:tnpt, 4) = fread(fidp, tnpt, "double")'; endif ## Copy rec index and type down val(2:tnpt, 5:6) = repmat (val(1, 5:6), tnpt-1, 1); otherwise ## E.g., null shape (0) ## Keep track of null shapes to avoid reading associated attributes if (val(1, 6) == 0) nullsh = [ nullsh ir ]; rincl = 0; elseif (abs(val(1, 6)) > 31) error (["shaperead: unexpected shapetype value %f for feature ", ... "# %d\n Looks like a faulty shape file."], ... val(1, 6), ir); endif endswitch ## Check if (X, Y) are valid coordinates if (any (abs (val(:, 1:2)) > 1.797e308)) ## Probably +/- Inf rincl = 0; if (dbug) printf ("shape# %d has no finite XY coordinates, skipped\n", ir); endif ## Detect if shape lies (partly) within or completely out of BoundingBox. ## Null shapes are automatically skipped elseif (! isempty (s_bbox)) ## Just check if any shape feature bounding box corner lies in s_bbox tbox = [tbbox(1) tbbox(2); tbbox(1) tbbox(4); ... tbbox(3) tbbox(4); tbbox(3) tbbox(2); tbbox(1) tbbox(2)]; rincl = 0; ## For polygons, polylines & multipatches: if (ismember (val(1, 6), [3, 13, 23, 5, 15, 25, 31])) ## Polygon/line ## To avoid undue CPU time for large shapes we take a shortcut: ## Check if shape feature lies in BoundingBox... [a, b] = inpolygon (tbox(:, 1), tbox(:, 2), sbox(:, 1), sbox(:, 2)); ## ...or BoundingBox lies in polyline/gon. Faster than indiv. points [c, d] = inpolygon (sbox(:, 1), sbox(:, 2), tbox(:, 1), tbox(:, 2)); if (any ([a; b; c; d])) ## At least one of the shape item bbox corners lies within s_bbox rincl = 1; bb_union = unique ([bb_union val(1, 5)]); ## FIXME still the case of polygon edges intersecting bounding box ## w/o vertices inside bounding box. Clipping required for that endif elseif (ismember (val(1, 6), [1, 11, 21])) ## (Multi-)Point ## Simply select all points within or on boundaries [a, b] = inpolygon (val(:, 1), val(:, 2), sbox(:, 1), sbox(:, 2)); val = val(find(a), :); tnpt = size (val, 1); if (tnpt) rincl = 1; endif endif ## If clipping has been selected, clip all parts of the shape feature if (rincl && clip) ## What to do depends on shape type. Null and MultiPatch aren't clipped switch val(1, 6) case {3, 13, 23, 5, 15, 25, 31} ## Polyline/gon, Multipatch ## Temporarily silence Octave a bit, then call clippln warning ("off", "Octave:broadcast", "local"); [val, tnpt, tnpr] = clippln (val, tnpt, tnpr, sbox, val(1, 6)); otherwise warning ("shaperead: unknown shape type found (%d) - ignored\n", ... val(1, 6)); rincl = 0; val = []; endswitch if (isempty (val)) ## Don't include it and remove last added bb_union entry bb_union(end) = []; rincl = 0; else ## Update bounding box tbbox(1) = min (val(:, 1)); tbbox(2) = min (val(:, 2)); tbbox(3) = max (val(:, 1)); tbbox(4) = max (val(:, 2)); endif endif endif ## What to do with the val data, if to be included if (rincl) ## Keep track of nr of shape features read ++nshp; ## M-values < -1e39 really mean absent values im = find (val(:, 4) < -1e39); val(im, 4) = NaN; if (outopts < 3) ## Prepare an Octave or Matlab style struct optimized for fast ## plotting by inserting a NaN row after each polyline/-gon part nn = size (tnpr, 2); valt = NaN(tnpt + nn - 1, 6); ipt = 1; ttnpr = [tnpr(1, :) tnpt]; dtnpr = diff (ttnpr); for ii=2:numel (ttnpr) valt(ipt:ipt+dtnpr(ii-1)-1, :) = val(ttnpr(ii-1)+1:ttnpr(ii), :); ipt += dtnpr(ii-1) + 1; endfor val = valt; tnpr(1, :) = (tnpr(1, :) + [0:numel(dtnpr)-1]); endif ## Shape either included by default or it lies in requested BoundingBox switch outopts case {0, 1} ## Return a ML compatible mapstruct. Attributes will be added later if (ign_mz && val(1, 6) >= 10) printf ("shaperead: M and Z values ignored for ml-style output\n"); ign_mz = 0; endif switch val(1, 6) case {1, 11, 21} ## Point outs(end+1, 1).Geometry = "Point"; case {8, 18, 28} ## Multipoint outs(end+1, 1).Geometry = "MultiPoint"; case {3, 13, 23} ## Polyline outs(end+1, 1).Geometry = "Line"; case {5, 15, 25} ## Polygon outs(end+1, 1).Geometry = "Polygon"; otherwise if (outopts == 1) ## "Extended" ML-style output struct if (val(1, 6) == 31) ## MultiPatch outs(end+1, 1).Geometry = "MultiPatch"; outs(end, 1).Parts = tnpr; endif else if (! unsupp) warning (["shaperead: shapefile contains unsupported ", ... "shape types\n"]); outs = oatt = []; return endif outs(end+1, 1).Geometry = val(1, 6); endif endswitch ## Omit BoundingBox for Point if (all ([1, 11, 21] - val(1, 6))) outs(end).BoundingBox = reshape (tbbox(1:4), 2, [])'; endif if (s_geo) outs(end, 1).Lon = val(:, 1)'; outs(end, 1).Lat = val(:, 2)'; else outs(end, 1).X = val(:, 1)'; outs(end, 1).Y = val(:, 2)'; endif ## (ML-incompatible) add Z- and optional M-values, if any if (outopts == 1 && any (isfinite (val(:, 4)))) outs(end, 1).M = val(:, 4)'; ## FIXME Decision needed if field Geometry should reflect the type ## outs{end}.Geometry = [ outs{end}.Geometry "M"]; endif if (outopts == 1 && any (isfinite (val(:, 3)))) outs(end, 1).Z = val(:, 3)'; ## FIXME Decision needed if field Geometry should reflect the type ## outs{end}.Geometry = [ outs{end}.Geometry "Z"]; endif ## (ML-incompatible) add Z- and optional M-values, if any if (dbug) ## Add a field with shape feature identifier for boundingbox outs(end, 1).___Shape_feature_nr___ = val(1, 5); endif case {2} ## Return an Octave style struct. ## Append to vals array; keep track of appended nr. of rows lvals = size (vals, 1); lval = size (val, 1); if ((size (vals, 1) - ivals) < lval) ## Increase size of vals vals = [ vals; NaN(BUFSIZE, 6) ]; endif vals(ivals:ivals+lval-1, :) = val; idx = [idx ; ivals]; ivals += lval; ## Add a row of NaNs vals(ivals, :) = NaN(1,6); ++ivals; ## Append the other arrays npt = [npt; tnpt]; if (isempty (npr)) npr = {tnpr}; else npr = [npr; {tnpr}]; endif bbox = [bbox; tbbox]; case {3} ## Return a compressed Octave style struct. ## Simply append to vals array; keep track of appended nr. of rows lvals = size (vals, 1); lval = size (val, 1); if ((size (vals, 1) - ivals) < lval) ## Increase size of vals vals = [ vals; NaN(BUFSIZE, 6) ]; endif vals(ivals:ivals+lval-1, :) = val; idx = [idx ; ivals]; ivals += lval; ## Append the other arrays npt = [npt; tnpt]; if (isempty (npr)) npr = {tnpr}; else npr = [npr; {tnpr}]; endif bbox = [bbox; tbbox]; otherwise endswitch endif else ## Record not in s_recs list, skip rest of record fread (fidp, (rlen*2), "char=>char"); endif ## Next .shp record ++ir; until (ftell (fidp) > flngt - 3 || (have_shx && ir > numel (s_recs))); ## i.e., within last ## file bytes or all ## req. records read fclose (fidp); ## If no shape was read, or none fitted within BoundingBox, return empty if (nshp < 1) outs = oatt = {}; return; endif ## ------------------------ Post-processing ------------------------ if (outopts > 1) ## Octave-style outstruct. Truncate vals to proper length vals = vals(1:ivals-1, :); if (outopts == 2 && ! isempty (vals)) ## Remove last NaN row vals(end, :) = []; endif if (isempty (vals)) s_recs = 0; endif endif if (dbug) if (outopts <= 1) ii = numel (outs); else ii = numel (npt); endif printf ("\n%d records read. \n", ii); endif ## For Octave style output, add separate arrays to output struct if (outopts >= 2) outs.shpbox = shpbox; outs.vals = vals; outs.bbox = bbox; outs.npt = npt; outs.npr = npr; outs.idx = idx; ## Clear memory (for very large shape files) clear shpbox vals bbox npt npr idx val; outs = setfield (outs, "fields", {"shpbox", "vals", "bbox", "npt", "npr"}); endif ## Clean up s_recs and bb_union if (! isempty (s_bbox)) s_recs = sort (unique (bb_union)); else s_recs = sort (unique (s_recs)); endif ## Weed out any null shape records to prevent reading their attributes if (! isempty (nullsh)) if (outopts >= 2 && ! isempty (s_recs)) s_recs = [1:numel (npt)]; endif s_recs (ismember (nullsh, s_recs)) = []; endif ## ---------------------- 3. .dbf ---------------------- if (iscell (s_atts) && isempty (s_atts)) ## {} indicates no attributes to be read. Morph into "" return; endif ## Check if dbfread is available if (isempty (which ("dbfread"))) printf ("shaperead: dbfread function not found. No attributes will be added.\n"); printf (" (io package installed and loaded?)\n"); oatt = {}; else ## Try to read the .dbf file try atts = dbfread ([ bname ".dbf" ], s_recs, s_atts); if (! isempty (atts)) if (outopts < 2) ## First check if any attributes match fieldnames; if so, pre-/append "_" tags = {"Geometry", "BoundingBox", "X", "Y", "Lat", "Lon"}; for ii=1:numel (tags) idx = find (strcmp (tags{ii}, atts(1, :))); if (! isempty (idx)) atts(1, idx) = ["_" atts{1, idx} "_"]; endif endfor ## Matlab style map-/geostruct. Divide attribute values over struct elems if (nargout < 2) ## Attributes appended to outs struct for ii=1:size (atts, 2) [outs.(atts{1, ii})] = deal (atts(2:end, ii){:}); endfor oatt = []; else ## Attributes separately in oatt struct oatt(size (atts, 1) - 1).(atts{1, 1}) = []; for ii=1:size (atts, 2) [oatt.(atts{1, ii})] = deal (atts(2:end, ii){:}); endfor oatt = oatt'; endif else ## Octave output struct. Add attributes columns as struct fields ## Check if any attributes match fieldnames; if so, pre-/append "_" tags = {"shpbox", "vals", "bbox", "npt", "npr", "idx", "Geometry", ... "BoundingBox", "X", "Y", "Lat", "Lon"}; for ii=1:numel (tags) idx = find (strcmp (tags{ii}, atts(1, :))); if (! isempty (idx)) atts(1, idx) = ["_" atts{1, idx} "_"]; endif endfor for ii=1:size (atts, 2) outs.fields(end+1) = atts{1, ii}; if (islogical (atts{2, ii}) || isnumeric (atts{2, ii})) outs = setfield (outs, atts{1, ii}, cell2mat (atts(2:end, ii))); else outs = setfield (outs, atts{1, ii}, atts(2:end, ii)); endif endfor atts = []; endif endif catch printf ("shaperead: file %s couldn't be read;\n", [ bname ".dbf" ]); printf (" no attributes appended\n"); end_try_catch endif endfunction function has_M = checkM (fidp, ft, shpbox) has_M = true; ## Check if we do have M-values. If so, the next 3 4-byte words ## comprise the next record nr, rec length and shape type fptr = ftell (fidp); tmp = fread (fidp, 2, "int32", 0, "ieee-be"); tmp(3) = fread (fidp, 1, "int32"); if (tmp(1) == 2 && tmp(3) == ft) ## Looks like next record header + next shape feature type => no M has_M = false; shpbox.M(1) = 0; shpbox.M(2) = 0; endif fseek (fidp, fptr, "bof"); endfunction ## Only check input validation. I/O is tested in shapewrite.m %!error shaperead ('tst.shp', 'j'); %!error shaperead ('tst.shp', 7); %!error shaperead ('tst.shp', 'deb') %!error < property name expected> shaperead ('tst.shp', "ml", []); %!error shaperead ('tst.shp', 'deb', {}); mapping-1.4.3/inst/PaxHeaders/geodeticLatitudeFromParametric.m0000644000000000000000000000006215005124246021477 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/geodeticLatitudeFromParametric.m0000644000175000017500000000720015005124246022012 0ustar00philipphilip## Copyright (C) 2018-2022 Philip Nienhuis ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{phi} =} geodeticLatitudeFromParametric (@var{beta}, @var{flattening}) ## @deftypefnx {Function File} {@var{phi} =} geodeticLatitudeFromParametric (@var{beta}, @var{flattening}, @var{angleUnit}) ## Returns geodetic latitude (phi) given parametric latitude and flattening. ## ## Parametric latitude (@var{beta}) is also known as a reduced latitude. ## The default input and output is in degrees; use optional third parameter ## @var{angleUnit} for radians. @var{beta} can be a scalar, vector, matrix ## or any ND array. @var{flattening} must be a scalar value in the interval ## [0..1). ## ## Examples: ## Scalar input: ## @example ## phi = geodeticLatitudeFromParametric (45, 0.0033528) ## => phi = ## 45.096 ## @end example ## ## Also can use radians: ## @example ## phi = geodeticLatitudeFromParametric (pi/4, 0.0033528, "radians") ## => phi = ## 0.78708 ## @end example ## ## Vector Input: ## @example ## beta = 35:5:45; ## phi = geodeticLatitudeFromParametric (beta, 0.0033528) ## => phi = ## 35.09 40.095 45.096 ## @end example ## ## @seealso{geocentricLatitude, geodeticLatitudeFromGeocentric, parametricLatitude} ## @end deftypefn ## Function supplied by anonymous contributor, see: ## https://savannah.gnu.org/patch/index.php?9640 function phi = geodeticLatitudeFromParametric (beta, flattening, angleUnit="degrees") if (nargin < 2) print_usage (); endif if (! isnumeric (beta) || ! isreal (beta) || ... ! isnumeric (flattening) || ! isreal (flattening)) error ("geodeticLatitudeFromParametric : numeric input expected"); elseif (! isscalar (flattening)) error ("geodeticLatitudeFromParametric: scalar value expected for flattening"); elseif (flattening < 0 || flattening >= 1) error ("geodeticLatitudeFromParametric: flattening must lie in the real interval [0..1)" ); elseif (! ischar (angleUnit) ||! ismember (lower (angleUnit(1)), {"d", "r"})) error ("geodeticLatitudeFromParametric: angleUnit should be one of 'degrees' or 'radians'"); endif if (strncmpi (angleUnit, "r", 1) == 1) phi = atan2 (tan (beta), (1 - flattening)) ; else phi = atan2d (tand (beta), (1 - flattening)) ; endif endfunction %!test %! earth_flattening = 0.0033528 ; %! assert ( geodeticLatitudeFromParametric (45, earth_flattening), 45.0962122, 10e-6); %! assert ( geodeticLatitudeFromParametric (pi/4, earth_flattening, 'radians'), 0.78708, 10e-6); %!error geodeticLatitudeFromParametric (0.5, "flat") %!error geodeticLatitudeFromParametric (0.5, 5i) %!error geodeticLatitudeFromParametric ("beta", 0.0033528) %!error geodeticLatitudeFromParametric (5i, 0.0033528 ) %!error geodeticLatitudeFromParametric ([45 50], [0.7 0.8]) %!error geodeticLatitudeFromParametric (45, 1) %!error geodeticLatitudeFromParametric (45, 0.0033528, "km") mapping-1.4.3/inst/PaxHeaders/deg2sm.m0000644000000000000000000000006215005124246014545 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/deg2sm.m0000644000175000017500000000452415005124246015066 0ustar00philipphilip## Copyright (C) 2013-2022 Alexander Barth ## Copyright (C) 2018-2022 Philip Nienhuis ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{sm} =} deg2sm (@var{deg}) ## @deftypefnx {Function File} {@var{sm} =} deg2sm (@var{deg}, @var{radius}) ## @deftypefnx {Function File} {@var{sm} =} deg2sm (@var{deg}, @var{sphere}) ## Converts angle n degrees to distance in statute miles by multiplying angle ## with radius. ## ## Calculates the distances @var{sm} in a sphere with @var{radius} (also in ## statute miles) for the angles @var{deg}. If unspecified, radius defaults to ## 3958 sm, the mean radius of Earth. ## ## Alternatively, @var{sphere} can be one of "sun", "mercury", "venus", "earth", ## "moon", "mars", "jupiter", "saturn", "uranus", "neptune", or "pluto", in ## which case radius will be set to that object's mean radius. ## ## @seealso{deg2km, deg2nm, km2rad, km2deg, ## nm2deg, nm2rad, rad2km, rad2nm, rad2sm, sm2deg, sm2rad} ## @end deftypefn ## Built with insight from ## Author: Alexander Barth ## Adapted from deg2km.m by Anonymous contributor, see patch #9709 function sm = deg2sm (deg, radius = "earth") ## Check arguments if (nargin < 1 || nargin > 2) print_usage(); elseif (ischar (radius)) ## Get radius of sphere with its default units (km) radius = km2sm (spheres_radius (radius)); ## Check input elseif (! isnumeric (radius) || ! isreal (radius)) error ("deg2sm: RADIUS must be a numeric scalar"); endif sm = (deg2rad (deg) * radius); endfunction %!test %!assert (sm2deg (deg2sm (10)), 10, 10*eps); %!assert (sm2deg (deg2sm (10, 80), 80), 10, 10*eps); %!assert (sm2deg (deg2sm (10, "pluto"), "pluto"), 10, 10*eps); %!error deg2sm (5, 5i) mapping-1.4.3/inst/PaxHeaders/validateLengthUnit.m0000644000000000000000000000006215005124246017157 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/validateLengthUnit.m0000644000175000017500000002126715005124246017503 0ustar00philipphilip## Copyright (C) 2014-2022 Carnë Draug ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {} validateLengthUnit (@var{unit}) ## @deftypefnx {Function File} {} validateLengthUnit (@var{unit}, @var{ind}) ## @deftypefnx {Function File} {} validateLengthUnit (@var{unit}, @var{func}) ## @deftypefnx {Function File} {} validateLengthUnit (@var{unit}, @var{func}, @var{name}) ## @deftypefnx {Function File} {} validateLengthUnit (@var{unit}, @var{func}, @var{name}, @var{ind}) ## Check validity and standardize unit of length. ## ## Confirms that the argument @var{input} is a valid length unit as ## described on the table below, and returns a string with its standard ## name. If @var{unit} is not a valid length unit, throws an error with ## a message following the Octave guidelines. For a more informative error ## message, the function name @var{func}, the argument name @var{name}, ## and its position in the input @var{ind} can be defined. ## ## @table @asis ## @item @qcode{"meter"} ## m, meter(s), metre(s) ## ## @item @qcode{"centimeter"} ## cm, centimeter(s), centimetre(s) ## ## @item @qcode{"millimeter"} ## mm, millimeter(s), millimetre(s) ## ## @item @qcode{"micron"} ## micron(s) ## ## @item @qcode{"kilometer"} ## km, kilometer(s), kilometre(s) ## ## @item @qcode{"nautical mile"} ## nm, naut mi, nautical mile(s) ## ## @item @qcode{"foot"} ## ft, international ft, foot, international foot, feet, international feet ## ## @item @qcode{"inch"} ## in, inch, inches ## ## @item @qcode{"yard"} ## yd, yds, yard(s) ## ## @item @qcode{"mile"} ## mi, mile(s), international mile(s) ## ## @item @qcode{"U.S. survey foot"} ## sf, survey ft, US survey ft, U.S. survey ft, survey foot, US survey foot, ## U.S. survey foot, survey feet, US survey feet, U.S. survey feet ## ## @item @qcode{"U.S. survey mile (statute mile)"} ## sm, survey mile(s), statute mile(s), US survey mile(s), U.S. survey mile(s) ## ## @item @qcode{"Clarke's foot"} ## Clarke's foot, Clarkes foot ## ## @item @qcode{"German legal metre"} ## German legal metre, German legal meter ## ## @item @qcode{"Indian foot"} ## Indian foot ## ## @end table ## ## @seealso{units, unitsratio, validateattributes, validatestring} ## @end deftypefn ## Author: Carnë Draug function std_unit = validateLengthUnit (unit, varargin) ## keep it persistent to save us the trouble of building the struct ## each time we are called persistent units = struct ( ## keys are all lowercase since the search must be case-insensitive "m", "meter", "meter", "meter", "meters", "meter", "metre", "meter", "metres", "meter", "cm", "centimeter", "centimeter", "centimeter", "centimeters", "centimeter", "centimetre", "centimeter", "centimetres", "centimeter", "mm", "millimeter", "millimeter", "millimeter", "millimeters", "millimeter", "millimetre", "millimeter", "millimetres", "millimeter", "micron", "micron", "microns", "micron", "km", "kilometer", "kilometer", "kilometer", "kilometers", "kilometer", "kilometre", "kilometer", "kilometres", "kilometer", "nm", "nautical mile", "naut mi", "nautical mile", "nautical mile", "nautical mile", "nautical miles", "nautical mile", "ft", "foot", "international ft", "foot", "foot", "foot", "international foot", "foot", "feet", "foot", "international feet", "foot", "in", "inch", "inch", "inch", "inches", "inch", "yd", "yard", "yds", "yard", "yard", "yard", "yards", "yard", "mi", "mile", "mile", "mile", "miles", "mile", "international mile", "mile", "international miles", "mile", "sf", "U.S. survey foot", "survey ft", "U.S. survey foot", "us survey ft", "U.S. survey foot", "u.s. survey ft", "U.S. survey foot", "survey foot", "U.S. survey foot", "us survey foot", "U.S. survey foot", "u.s. survey foot", "U.S. survey foot", "survey feet", "U.S. survey foot", "us survey feet", "U.S. survey foot", "u.s. survey feet", "U.S. survey foot", "sm", "U.S. survey mile (statute mile)", "survey mile", "U.S. survey mile (statute mile)", "survey miles", "U.S. survey mile (statute mile)", "statute mile", "U.S. survey mile (statute mile)", "statute miles", "U.S. survey mile (statute mile)", "us survey mile", "U.S. survey mile (statute mile)", "us survey miles", "U.S. survey mile (statute mile)", "u.s. survey mile", "U.S. survey mile (statute mile)", "u.s. survey miles", "U.S. survey mile (statute mile)", "u.s. survey mile (statute mile)", "U.S. survey mile (statute mile)", "clarke's foot", "Clarke's foot", "clarkes foot", "Clarke's foot", "german legal metre", "German legal metre", "german legal meter", "German legal metre", "indian foot", "Indian foot" ); ## Built start of error message from the extra optional arguments func_name = ""; arg_id = "input"; if (nargin < 1) print_usage () elseif (nargin > 1) second = varargin{1}; if (ischar (second)) func_name = [second ": "]; elseif (nargin == 2 && isindex (second)) arg_id = sprintf ("input #%i", second); else error ("validateLengthUnit: 2nd input argument must be IND or FUNC"); endif if (nargin > 2) arg_id = varargin{2}; if (! ischar (arg_id)) error ("validateLengthUnit: NAME must be a string"); endif if (nargin > 3) arg_ind = varargin{3}; if (! isindex (arg_ind)) error ("validateLengthUnit: IND must be a positive integer"); endif arg_id = sprintf ("%s (argument #%i)", arg_id, arg_ind); endif endif endif if (! ischar (unit)) ## if it's not a string, error message must be different error ("%s%s must be a string", func_name, arg_id); endif lunit = tolower (unit); if (isfield (units, lunit)) std_unit = units.(lunit); else error ("%sunknown unit `%s' for %s", func_name, unit, arg_id); endif endfunction %!error validateLengthUnit ("bad", 7) %!error validateLengthUnit ("bad", "foo") %!error validateLengthUnit ("bad", "foo", "ARG") %!error validateLengthUnit ("bad", "foo", "ARG", 7) %!error validateLengthUnit (9) %!error validateLengthUnit (9, 7) %!error validateLengthUnit (9, "foo") %!error validateLengthUnit (9, "foo", "ARG") %!error validateLengthUnit (9, "foo", "ARG", 7) ## typical usage and case insensitivity %!assert (validateLengthUnit ("m"), "meter") %!assert (validateLengthUnit ("meter"), "meter") %!assert (validateLengthUnit ("meters"), "meter") %!assert (validateLengthUnit ("mETErs"), "meter") ## names with spaces and dots %!assert (validateLengthUnit ("us survey feet"), "U.S. survey foot") %!assert (validateLengthUnit ("US survey feet"), "U.S. survey foot") %!assert (validateLengthUnit ("U.S. survey feet"), "U.S. survey foot") %!assert (validateLengthUnit ("u.s. survey feet"), "U.S. survey foot") ## names with apostrophes %!assert (validateLengthUnit ("clarke's foot"), "Clarke's foot") mapping-1.4.3/inst/PaxHeaders/n2ecc.m0000644000000000000000000000006215005124246014356 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/n2ecc.m0000644000175000017500000000414615005124246014677 0ustar00philipphilip## Copyright (C) 2018-2022 Philip Nienhuis ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or (at ## your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{ecc} =} n2ecc (@var{n}) ## This returns the eccentricity given the third flattening (n). ## ## Examples: ## ## Scalar input: ## @example ## n_earth = 0.0016792; ## ecc_earth = n2ecc (n_earth) ## => ecc_earth = 0.081819 ## @end example ## ## Vector input: ## @example ## n_vec = [ 0.0016792 0.033525 ]; ## ecc = n2ecc (n_vec) ## => ecc = ## 0.081819 0.35432 ## @end example ## ## @seealso{n2ecc} ## @end deftypefn ## Function supplied by anonymous contributor, see: ## https://savannah.gnu.org/patch/index.php?9566 ## For background see https://en.wikipedia.org/wiki/Flattening function ecc = n2ecc (n) if (nargin < 1) print_usage (); end if (! isnumeric (n) || ! isreal (n) ) error ("n2ecc: numeric input expected"); elseif (any (n < 0) || any (n > 1)) error ("n2ecc: n should lie in the real interval [0..1]" ) else ecc = sqrt (4 * n ./ (1 + n) .^2); end endfunction %!test %! %! n_earth = 0.001679221647179929; %! n_jupiter = 0.03352464537391420; %! n_vec = [ n_earth n_jupiter ]; %! assert (n2ecc (n_earth) , .081819221456 , 10e-12); %! assert (n2ecc (n_vec), [0.08181922 0.3543164], 10e-8) %!error n2ecc ("n") %!error n2ecc (0.5 + 3i) %!error n2ecc (-1) %!error n2ecc (2) %!error n2ecc (-Inf) %!error n2ecc (Inf) mapping-1.4.3/inst/PaxHeaders/vincenty.m0000644000000000000000000000006215005124246015223 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/vincenty.m0000644000175000017500000001455615005124246015552 0ustar00philipphilip## Copyright (C) 2014-2022 Alfredo Foltran ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {} @var{dist} = vincenty(@var{pt1}, @var{pt2}) ## @deftypefnx {Function File} {} @var{dist} = vincenty(@var{pt1}, @var{pt2}, @var{ellipsoid}) ## @deftypefnx {Function File} {[@var{dist}, @var{az}] = } {vincenty(@var{pt1}, @var{pt2})} ## @deftypefnx {Function File} {[@var{dist}, @var{az}] = } {vincenty(@var{pt1}, @var{pt2}, @var{ellipsoid})} ## Calculates the distance (in meters) between two (sets of) locations on ## an ellipsoid. ## ## The formula devised by Thaddeus Vincenty is used with an accurate ## ellipsoidal model of the earth (@var{ellipsoid}). The default ellipsoidal ## model is 'WGS84', which is the most globally accurate model. ## ## @var{pt1} and @var{pt2} are two-column matrices of the form [latitude longitude]. ## The units for the input coordinates angles must be degrees. ## Optional argument @var{ellipsoid} defines the reference ellipsoid to use. ## ## Sample values for @var{ellipsoid} are the following: ## ## @multitable @columnfractions .7 .3 ## @headitem Model @tab @var{ellipsoid} ## @item WGS 1984 (default) @tab referenceEllipsoid(7030) ## @item GRS 1980 @tab referenceEllipsoid(7019) ## @item G.B. Airy 1830 @tab referenceEllipsoid(7001) ## @item Internacional 1924 @tab referenceEllipsoid(7022) ## @item Clarke 1880 @tab referenceEllipsoid(7012) ## @item Australian Nat. @tab referenceEllipsoid(7003) ## @end multitable ## ## The sample model values are the following: ## ## @multitable @columnfractions .35 .20 .20 .25 ## @headitem Model @tab Major (km) @tab Minor (km) @tab 1 / f ## @item WGS 1984 @tab 6378.137 @tab 6356.7523142 @tab 298.257223563 ## @item GRS 1980 @tab 6378.137 @tab 6356.7523141 @tab 298.257222101 ## @item G.B. Airy 1830 @tab 6377.563396 @tab 6356.256909 @tab 299.3249646 ## @item Internacional 1924 @tab 6378.388 @tab 6356.911946 @tab 297.0 ## @item Clarke 1880 @tab 6378.249145 @tab 6356.51486955 @tab 293.465 ## @item Australian Nat. @tab 6378.1600 @tab 6356.774719 @tab 298.25 ## @end multitable ## ## Usage: ## @example ## >> vincenty ([37, -76], [37, -9]) ## ans = 5830.081 ## >> vincenty ([37, -76], [67, -76], referenceEllipsoid (7019)) ## ans = 3337.843 ## @end example ## ## @seealso{distance, referenceEllipsoid} ## @end deftypefn ## Author: Alfredo Foltran ## ## Octave style fixes and some re-coding to avoid sneaky errors by ## Philip Nienhuis function [dist, az] = vincenty (pt1, pt2, ellipsoid) if (nargin < 3) ellipsoid = referenceEllipsoid (7030); endif major = ellipsoid.SemimajorAxis; minor = ellipsoid.SemiminorAxis; f = ellipsoid.Flattening; ## Avoid confusion of length units impsed by ellipsoid, standardize on meters if (isfield (ellipsoid, "LengthUnit") && ! isempty (ellipsoid.LengthUnit)) major *= unitsratio ("meters", ellipsoid.LengthUnit); minor *= unitsratio ("meters", ellipsoid.LengthUnit); endif iter_limit = 20; pt1 = deg2rad (pt1); pt2 = deg2rad (pt2); [lat1 lng1] = deal (pt1(1), pt1(2)); [lat2 lng2] = deal (pt2(1), pt2(2)); delta_lng = lng2 - lng1; reduced_lat1 = atan ((1 - f) * tan (lat1)); reduced_lat2 = atan ((1 - f) * tan (lat2)); [sin_reduced1 cos_reduced1] = deal (sin (reduced_lat1), cos (reduced_lat1)); [sin_reduced2 cos_reduced2] = deal (sin (reduced_lat2), cos (reduced_lat2)); lambda_lng = delta_lng; lambda_prime = 2 * pi; i = 0; while (abs (lambda_lng - lambda_prime) > 10e-12 && i <= iter_limit) i++; [sin_lambda_lng cos_lambda_lng] = deal (sin (lambda_lng), cos (lambda_lng)); sin_sigma = sqrt ((cos_reduced2 * sin_lambda_lng) ^ 2 + ... (cos_reduced1 * sin_reduced2 - ... sin_reduced1 * cos_reduced2 * cos_lambda_lng) ^ 2); if (abs (sin_sigma < eps)) dist = 0; return; endif cos_sigma = (sin_reduced1 * sin_reduced2 + ... cos_reduced1 * cos_reduced2 * cos_lambda_lng); sigma = atan2 (sin_sigma, cos_sigma); sin_alpha = (cos_reduced1 * cos_reduced2 * sin_lambda_lng / sin_sigma); cos_sq_alpha = 1 - sin_alpha ^ 2; if (abs (cos_sq_alpha > eps)) cos2_sigma_m = cos_sigma - 2 * (sin_reduced1 * sin_reduced2 / cos_sq_alpha); else cos2_sigma_m = 0.0; ## Equatorial line endif C = f / 16.0 * cos_sq_alpha * (4 + f * (4 - 3 * cos_sq_alpha)); lambda_prime = lambda_lng; lambda_lng = (delta_lng + (1 - C) * f * sin_alpha * (sigma + ... C * sin_sigma * (cos2_sigma_m + C * cos_sigma * ... (-1 + 2 * cos2_sigma_m ^ 2)))); endwhile if (i > iter_limit) error("Inverse Vincenty's formulae failed to converge!"); endif u_sq = cos_sq_alpha * (major ^ 2 - minor ^ 2) / minor ^ 2; A = 1 + u_sq / 16384.0 * (4096 + u_sq * (-768 + u_sq * (320 - 175 * u_sq))); B = u_sq / 1024.0 * (256 + u_sq * (-128 + u_sq * (74 - 47 * u_sq))); delta_sigma = (B * sin_sigma * (cos2_sigma_m + B / 4. * (cos_sigma * ... (-1 + 2 * cos2_sigma_m ^ 2) - B / 6. * cos2_sigma_m * ... (-3 + 4 * sin_sigma ^ 2) * (-3 + 4 * cos2_sigma_m ^ 2)))); dist = minor * A * (sigma - delta_sigma); if (nargout() > 1) alpha1 = atan2 (cos_reduced2 * sin_lambda_lng, ... cos_reduced1 * sin_reduced2 - sin_reduced1 * ... cos_reduced2 * cos_lambda_lng); alpha2 = atan2 (cos_reduced1 * sin_lambda_lng, ... -sin_reduced1 * cos_reduced2 + cos_reduced1 * ... sin_reduced2 * cos_lambda_lng); az = rad2deg ([alpha1 alpha2]); endif endfunction %!test %! assert (vincenty ([37, -76], [37, -9]), 5830081.063, 1e-2); %!test %! assert (vincenty ([37, -76], [67, -76], referenceEllipsoid (7019)), ... %! 3337842.871, 1e-2) mapping-1.4.3/inst/PaxHeaders/dxfread.m0000644000000000000000000000006215005124246015001 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/dxfread.m0000644000175000017500000000460415005124246015321 0ustar00philipphilip## Copyright (C) 2016-2022 Philip Nienhuis ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . ## -*- texinfo -*- ## @deftypefn {} {@var{dxf} =} dxfread (@var{fname}) ## Read a DXF file (text file) into a Nx3 cell array. ## ## @var{fname} is the file name or full path name of a text format (not ## binary) DXF file, with or without "dxf" extension. ## ## Output variable @var{dxf} is a cell array with DXF codes in column 1, ## the corresponding DXF text info (or empty string) in column 2, and ## corresponding numeric values (or NaN) in column 3. Use dxfparse for ## converting the output into a DXF drawing struct or separate mapstructs ## for each ENTITY type in the DXF file. ## ## @seealso{dxfparse, dxfdraw} ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2016-01-25 function [dxf] = dxfread (fname) if (! ischar (fname)) print_usage (); endif [pth, fn, ext] = fileparts (fname); if (isempty (ext)) ext = ".dxf"; fname = [fname ext]; elseif (! strcmpi (ext, ".dxf")) error ("dxfread: file is no .DXF file"); endif fid = fopen (fname); if (fid < 0) error ("file %s not found", fname); else txt = fread (fid, Inf, "char=>char")'; fclose (fid); endif ## Assess EOL character eol = regexp (txt(1: min (2000, length (txt))), "\r\n", "match", "once"); if (isempty (eol)) eol = "\n"; endif ## DXF files comprise pairs of lines: 1st line = numeric code, 2nd = contents dxf = reshape (cell2mat ( ... regexp (txt, sprintf ('(\\d+)%s(.+?)%s', eol, eol), "tokens")), 2, [])'; ## Convert col 1 into numeric dxf(:, 1) = num2cell (str2double (dxf(:, 1))); ## Convert numeric entries in col2 into numeric col3 dxf(:, 3) = num2cell (str2double (dxf(:, 2))); dxf(! cellfun (@isnan, dxf(:, 3)), 2) = {""}; endfunction mapping-1.4.3/inst/PaxHeaders/majaxis.m0000644000000000000000000000006215005124246015020 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/majaxis.m0000644000175000017500000000541615005124246015342 0ustar00philipphilip## Copyright (C) 2018-2022 Philip Nienhuis ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{semimajoraxis} =} majaxis (@var{semiminoraxis}, @var{ecc}) ## Return the semimajor axis given the semiminoraxis (b) and eccentricity (e). ## ## Examples ## ## Scalar input: ## @example ## earth_b = 6356752.314245; ## meter ## earth_ecc = 0.081819221456; ## a = majaxis (earth_b, earth_ecc) ## => a = ## 6.3781e+06 ## @end example ## ## Vector input: ## @example ## planets_b = [ 6356752.314245 ; 66854000 ]; ## meter ## planets_ecc = [ 0.081819221456 ; 0.3543164 ]; ## planets_a = majaxis ( planets_b , planets_ecc ) ## => planets_a = ## 6.3781e+06 ## 7.1492e+07 ## @end example ## ## @seealso{minaxis} ## @end deftypefn ## Function supplied by anonymous contributor, see: ## https://savannah.gnu.org/patch/index.php?9566 ## For background see https://en.wikipedia.org/wiki/Flattening function a = majaxis (b, ecc) if (nargin < 2) print_usage (); end if (! isnumeric (b) || ! isreal (b) || ! isnumeric (ecc) || ! isreal (ecc)) error ( "majaxis : numeric input expected"); elseif (any (ecc < 0) || any (ecc > 1)) error ( "majaxis: eccentricity must lie in the real interval [0..1]" ) elseif ((length (b) != 1 && length (ecc) != 1) && ((size (b) != size (ecc)))) error ("majaxis: vectors must be the same size") else a = b ./ sqrt (1 - ecc .^ 2); end endfunction %!test %! %! earth_b = 6356752.314245; ## meter %! earth_ecc = 0.081819221456; %! assert ( majaxis (earth_b, earth_ecc), 6378137.01608, 10e-6); %! planets_b = [ 6356752.314245 ; 66854000 ]; ## meter %! planets_ecc = [ 0.081819221456 ; 0.3543164 ]; %! assert( majaxis (planets_b, planets_ecc), [ 6378137.01608; 71492000.609327 ], 10e-6 ); %!error majaxis (0.5, "ecc") %!error majaxis (0.5, 0.3 + 0.5i) %!error majaxis ("b", 0.5) %!error majaxis (0.3 + 0.5i , 0.5) %!error majaxis ([10; 10; 10], [0.5; 0; -0.5]) %!error minaxis ( [ 6356752.314245 ; 66854000 ] , [ 0.081819221456 ; 0.3543164 ]')mapping-1.4.3/inst/PaxHeaders/ned2ecef.m0000644000000000000000000000006215005124246015037 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/ned2ecef.m0000644000175000017500000001516415005124246015362 0ustar00philipphilip## Copyright (C) 2022 Philip Nienhuis ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{x}, @var{y}, @var{z} =} enu2ecef (@var{n}, @var{e}, @var{d}, @var{lat}, @var{lon}, @var{alt}) ## @deftypefnx {Function File} {@var{x}, @var{y}, @var{z} =} enu2ecef (@var{n}, @var{e}, @var{d}, @var{lat}, @var{lon}, @var{alt}, @var{spheroid}) ## @deftypefnx {Function File} {@var{x}, @var{y}, @var{z} =} enu2ecef (@var{n}, @var{e}, @var{d}, @var{lat}, @var{lon}, @var{alt}, @var{spheroid}, @var{angleUnit}) ## Convert local cartesian North, East, Down (NED) coordinates to Earth Centered ## Earth Fixed (ECEF) coordinates. ## ## Inputs: ## @itemize ## @item ## @var{n}, @var{e}, @var{d}: look angles and distance to target point ## (angle, angle, length). Length unit of @var{u} (height) is that of the ## used reference ellipsoid (see below). Can be scalars but vector or ## nD-array values are accepted if they have equal dimensions. ## ## @item ## @var{lat}, @var{lon}, @var{alt}: ellipsoid geodetic coordinates of ## observer location (angle, angle, length). Length unit of @var{alt} ## (height) is that of the used reference ellipsoid (see below). In case of ## multiple observer locations their numbers and dimensions should match those ## of the target points (i.e., one observer location for each target point). ## ## @item ## @var{spheroid}: referenceEllipsoid parameter struct, name or EPSG number; ## default is wgs84. Can be an empty string or empty numeric array ('[]') to ## indicate default value. ## ## @item ## @var{angleUnit}: string for angular units ('degrees' or 'radians', ## case-insensitive, just the first character will do). Default is 'degrees'. ## @end itemize ## ## Outputs: ## @itemize ## @item ## @var{x}, @var{y}, @var{z}: Earth Centered Earth Fixed (ECEF) coordinates. ## Length units are those of the used reference ellipsoid. ## @end itemize ## ## Examples ## @example ## [x, y, z] = ned2ecef (286.84, 186.28, -939.69, 42, -82, 200) ## x = 6.6093e+05 ## y = -4.7014e+06 ## z = 4.2466e+06 ## @end example ## ## With radians ## @example ## [x, y, z] = ned2ecef (286.84, 186.28, -939.69, pi/4, -pi/2, 200, ... ## "wgs84", "radians") ## x = 186.28 ## y = -4.5182e+06 ## z = 4.4884e+06 ## @end example ## ## @seealso{ecef2ned, ned2aer, ned2ecefv, ned2geodetic, referenceEllipsoid} ## @end deftypefn ## Function contributed by anonymous contributor, see: ## https://savannah.gnu.org/patch/index.php?9923 function [x, y, z] = ned2ecef (varargin) spheroid = ""; angleUnit = "degrees"; if (nargin < 6 || nargin > 8) print_usage(); elseif (nargin == 6) ## Assume lat, lon, alt, lat0, lon0, alt0 given elseif (nargin == 7) if (isnumeric (varargin{7})) ## EPSG spheroid code spheroid = varargin{7}; elseif (ischar (varargin{7})) if (! isempty (varargin{7}) && ismember (varargin{7}(1), {"r", "d"})) angleUnit = varargin{7}; else spheroid = varargin{7}; endif elseif (isstruct (varargin{7})) spheroid = varargin{7}; else error ("ned2ecef: spheroid or angleUnit expected for arg. #7"); endif elseif (nargin == 8) spheroid = varargin{7}; angleUnit = varargin{8}; endif n = varargin{1}; e = varargin{2}; u = varargin{3}; # Note multiplying by -1 makes it numeric so just use # -u for the function lat = varargin{4}; lon = varargin{5}; alt = varargin{6}; if (! isnumeric (e) || ! isreal (e) || ... ! isnumeric (n) || ! isreal (n) || ... ! isnumeric (u) || ! isreal (u) ||... ! isnumeric (lat) || ! isreal (lat) || ... ! isnumeric (lon) || ! isreal (lon) || ... ! isnumeric (alt) || ! isreal (alt)) error ("ned2ecef: numeric values expected for first 6 inputs."); endif if (! all (size (e) == size (n)) || ... ! all (size (n) == size (u))) ... error ("ned2ecef: non-matching dimensions of inputs."); endif if (! (isscalar (lat) && isscalar (lon) && isscalar (alt))) ## Check if for each test point a matching observer point is given if (! all (size (lat) == size (e)) || ... ! all (size (lon) == size (n)) || ... ! all (size (alt) == size (u))) error (["ned2ecef: non-matching dimensions of observer points and ", ... "target points"]); endif endif if (isnumeric (spheroid)) spheroid = num2str (spheroid); endif E = sph_chk (spheroid); [x, y, z] = enu2ecef (e, n, -u, lat, lon, alt, E, angleUnit); endfunction %!test %! [x, y, z] = ned2ecef (286.84, 186.28, -939.69, 42, -82, 200); %! assert ([x, y, z], [6.6093019515e5, -4.70142422216e6, 4.24657960122e6], 10e-6) %!test %! [x3, y3, z3] = ned2ecef (286.84, 186.28, -939.69, 0.733038285837618, -1.43116998663535, 200, "", "rad"); %! assert ([x3, y3, z3], [660.93019e3, -4701.42422e3, 4246.5796e3],10e-3) %!test %! [a, b, c] = ned2ecef (-923083.2, 355601.3, -1041016.4, 45.9132, 36.7484, 1877753.2); %! assert ([a, b, c], [5507528.8891, 4556224.1399, 6012820.7522], 1e-4) %!test %! [x,y,z] = ned2ecef( 1334.3, -2544.4, 360.0, 44.532, -72.782, 1699); %! assert ([x, y, z], [1345659.962, -4350890.986, 4452313.969], 1e-3); %!error ned2ecef("s", 25, 1e3, 0, 0, 0) %!error ned2ecef(3i, 25, 1e3, 0, 0, 0) %!error ned2ecef(33, "s", 1e3, 0, 0, 0) %!error ned2ecef(33, 3i, 1e3, 0, 0, 0) %!error ned2ecef(33, 25, "s", 0, 0, 0) %!error ned2ecef(33, 25, 3i, 0, 0, 0) %!error ned2ecef(33, 25, 1e3, "s", 0, 0) %!error ned2ecef(33, 25, 1e3, 3i, 0, 0) %!error ned2ecef(33, 25, 1e3, 0, "s", 0) %!error ned2ecef(33, 25, 1e3, 0, 3i, 0) %!error ned2ecef(33, 25, 1e3, 0, 0, "s") %!error ned2ecef(33, 25, 1e3, 0, 0, 3i) %!error ned2ecef ([1 1], [2 2]', [3 3], 4, 5, 6) %!error ned2ecef ([1 1], [2 2], [33], 4, 5, 6) %!error ned2ecef ([1 1], [2 2], [3 3], [4 4], 5, 6) %!error ned2ecef ([1 1], [2 2], [3 3], 4, [5 5], 6) %!error ned2ecef ([1 1], [2 2], [3 3], 4, 5, [6 6]) mapping-1.4.3/inst/PaxHeaders/nm2rad.m0000644000000000000000000000006215005124246014547 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/nm2rad.m0000644000175000017500000000440415005124246015065 0ustar00philipphilip## Copyright (C) 2014-2022 Pooja Rao ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{rad} =} nm2rad (@var{nm}) ## @deftypefnx {Function File} {@var{rad} =} nm2rad (@var{nm}, @var{radius}) ## @deftypefnx {Function File} {@var{rad} =} nm2rad (@var{nm}, @var{sphere}) ## Converts distance to angle by dividing distance by radius. ## ## Calculates the angles @var{rad} for the distances @var{nm} in a sphere with ## @var{radius} (also in nautical miles). If unspecified, radius defaults to 6371 km, ## the mean radius of Earth and is converted to nautical miles internally. ## ## Alternatively, @var{sphere} can be one of "sun", "mercury", "venus", "earth", ## "moon", "mars", "jupiter", "saturn", "uranus", "neptune", or "pluto", in ## which case radius will be set to that object mean radius. ## ## @seealso{km2rad} ## @end deftypefn ## Author: Pooja Rao function rad = nm2rad (nm, radius = "earth") ## This function converts nautical miles (nm) to radians (rad) ## Check arguments if (nargin < 1 || nargin > 2) print_usage(); elseif (ischar (radius)) ## Get radius of sphere and convert its default units (km) ## to nautical miles (nm) radius = km2nm (spheres_radius (radius)); ## Check input elseif (! isnumeric (radius) || ! isscalar (radius)) error ("nm2rad: RADIUS must be a numeric scalar"); endif rad = nm/radius; endfunction %!test %! ratio = unitsratio ('km','nm'); %! assert (nm2rad (10), km2rad (ratio*10), 10*eps); %! assert (nm2rad (10, 80), km2rad (ratio*10, ratio*80), 10*eps); %! assert (nm2rad (10, "pluto"), km2rad (ratio*10, "pluto"), 10*eps); mapping-1.4.3/inst/PaxHeaders/angltostr.m0000644000000000000000000000006215005124246015401 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/angltostr.m0000644000175000017500000002142715005124246015723 0ustar00philipphilip## Copyright (C) 2022 Philip Nienhuis ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . ## -*- texinfo -*- ## @deftypefn {} {@var{strs} =} angltostr (@var{angles}) ## @deftypefnx {} {@var{strs} =} angltostr (@var{angles}, @var{hemcode}) ## @deftypefnx {} {@var{strs} =} angltostr (@var{angles}, @var{hemcode}, @var{unit}) ## @deftypefnx {} {@var{strs} =} angltostr (@var{angles}, @var{hemcode}, @var{unit}, @var{prec}) ## Convert numerical angle values (Lat and/or Lon) into cellstr text values. ## ## Inputs: ## @itemize ## @item ## @var{angles} is a scalar or any array of angular values in degrees. In ## case @var{unit} is specified as radians, @var{angles} is supposed to be in ## radians as well. ## ## @item ## @var{hemcode} (optional), used for indicating the hemisphere, can be one ## of "ew", "ns", "pm" or "none" (default), all case-insensitive. Depending ## on the sign of the input angle(s), the output strings have a trailing "E", ## "W", "N" or "S" character in case of @var{hemcode} = "ew" or "ns", a ## leading "+"or "-" in case of @var{hemcode} = "pm", or just a leading "-" ## or negative output values in case of @var{hemcode} = "none". angltostr.m ## is forgiving: "we", "sn", "mp" and "no" are also accepted and any empty ## value will be recognized as "none". ## ## @item ## @var{unit} (optional, case-insensitive) describes the output format. ## * "degrees" (default): decimal degrees (~ -110.5320) @* ## * "degrees2dm": integer degrees and real minutes (94°55.980'W) @* ## * "degrees2dms": integer degrees and minutes and real seconds (~ 4°55'58.8"S) @* ## * "radians": real radian "values" (~ +3.141593) ## ## @item ## @var{prec} indicates the desired number of decimal places; it's equal to ## abs(@var{prec}). ## @end itemize ## ## The output is a cell array of strings, one cell for each angle value, the ## same shape as the input array. To convert it to more Matlab-compatible ## output, just apply char() to get a char string or char array. ## ## Furthermore, unlike its Matlab sibling angl2str, angltostr will map ## output values into the [-180, 180] interval and adjust output hemisphere ## indicators ("E", "W", "N", "S" or just "-" or "+") accordingly. For ## latitudes this works similarly only if "ns" was specified for @var{hemcode}; ## in all other cases output must be postprocessed manually to map absolute ## latitudes > 90 degrees into (180-lat) * sign(lat); analogously for radians. ## ## @seealso{angl2str, str2angle} ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2020-05-19 function str = angltostr (ang, hemcode="none", unit="degrees", acc=-2) if (nargin < 1 || nargin > 4) print_usage (); elseif (! isnumeric (ang) || ! isreal (ang)) error ("ang2str: numeric real input expected for first argument"); elseif (! isempty (hemcode) && ! ischar (hemcode)) error (" angltostr: character value expected for arg #2"); elseif (! isempty (unit) && ! ischar (unit)) error (" angltostr: character value expected for arg. #3 (unit)"); elseif (! isnumeric (acc) || ! isreal (acc)) error ("ang2str: numeric real input expected for 4th argument"); endif if (isempty (unit)) unit = "degrees"; endif ## Hemisphere codings if (isempty (hemcode)) hemcode = "none"; endif ## Be a bit forgiving as regards unit indicators ih = mod (find (ismember ({"ew", "ns", "pm", "none", ... "we", "sn", "mp", "no"}, lower (hemcode))) - 1, 4) + 1; if (isempty (ih)) error (["angltostr: unknown signcode (arg.#2): %s, should be one of ", ... "'ew', 'ns', 'pm' or 'none'"], hemcode); endif ## Prepare for finding proper hemisphere israd = strcmpi (unit, "radians"); if (israd) ang = rad2deg (ang); endif ## Wrap angles into [-180, 180] and latitudes (if detected) in [-90 90] ang = wrapTo180 (ang); if (ih == 2) ## Normalize latitudes iflp = abs (ang) > 90; ang(iflp) = (180 - abs (ang(iflp))) .* sign (ang(iflp)); endif if (israd) ang = deg2rad (ang); endif ## Split up in degrees, minutes and seconds degs = sign (ang) .* floor (abs (ang)); mins = abs (ang - degs) * 60; secs = (mins - floor (mins)) * 60; is = sign (ang); ## Set zero values to positive is(abs(is) < 1) = 1; is (is < 0) = 0; ang = abs (ang); degs = abs (degs); ## Nr. of decimals to print decs = abs (acc); wdth = decs + 3; if (decs <= 0) wdth--; endif ## Hemisphere specific leading and trailing characters hc = {" ", " ", " W", " E"; ... " ", " ", " S", " N"; ... "-", "+", "", ""; ... "-", " ", "", ""}; ## Print the strings str = str = cell (size (ang)); switch (unit) case "degrees" fmt = sprintf ("%%%d.%df°", wdth+1, decs); for ii=1:numel (ang) str{ii} = sprintf (fmt, ang(ii)); endfor case "degrees2dm" fmt = sprintf ("%%3d°_%%%d.%df'", wdth, decs); for ii=1:numel (ang) str{ii} = sprintf (fmt, degs(ii), mins(ii)); endfor case "degrees2dms" mins = floor (mins); fmt = sprintf ("%%3d°_%%2d'_%%%d.%df\"", wdth, decs); for ii=1:numel (ang) str{ii} = sprintf (fmt, degs(ii), mins(ii), secs(ii)); endfor case "radians" fmt = sprintf ("%%%d.%df_R", wdth, decs); for ii=1:numel (ang) str{ii} = sprintf (fmt, ang(ii)); endfor otherwise error ("angltostr: unknown unit code (arg #3) - %s", unit); endswitch str = strrep (str, " ", "0"); str = strrep (str, "_", " "); for ii=1:numel (ang) str{ii} = sprintf ([" %s%s%s "], hc{ih, 1+is(ii)}, str{ii}, hc{ih, 3+is(ii)}); endfor str = regexprep (str, '^ ([-+ ])(0)(.*)$', " $1$3"); if (! strcmpi (unit, "radians")) str = regexprep (str, '^ ([-+ ])(0)(.*)$', " $1$3"); else str = regexprep (str, '^[ ]{1}(.*)$', "$1"); endif if (ih <= 2) str = regexprep (str, '^[ ]{1}(.*)$', "$1"); endif endfunction %!test %!shared ang %! ang = [-291.43 -180.0, -110.5320, -85.5, -80.425, -4.9330, 0, 3.0104, 90.0001, 180.0000, 233.425]; %! str = angltostr (ang, "none", "degrees", -3); %! res = {" 68.570° ", " -180.000° ", " -110.532° ", " -85.500° ", ... %! " -80.425° ", " -4.933° ", " 0.000° ", " 3.010° ", ... %! " 90.000° ", " 180.000° ", " -126.575° "}; %! assert (str, res); %!test %! str = angltostr (ang, "ew", "degrees2dm", -3); %! res = {" 68° 34.200' E ", " 180° 00.000' W ", " 110° 31.920' W ", ... %! " 85° 30.000' W ", " 80° 25.500' W ", " 4° 55.980' W ", ... %! " 0° 00.000' E ", " 3° 00.624' E ", " 90° 00.006' E ", ... %! " 180° 00.000' E ", " 126° 34.500' W "}; %! assert (str, res); %!test %! str = angltostr (ang, "NS", "degrees2dms", -1); %! res = {" 68° 34' 12.0\" N ", " 0° 00' 00.0\" N ", " 69° 28' 04.8\" S ", ... %! " 85° 30' 00.0\" S ", " 80° 25' 30.0\" S ", " 4° 55' 58.8\" S ", ... %! " 0° 00' 00.0\" N ", " 3° 00' 37.4\" N ", " 89° 59' 59.6\" N ", ... %! " 0° 00' 00.0\" N ", " 53° 25' 30.0\" S "}; %! assert (str, res); %!test %! str = angltostr (ang, "EW", "degrees2dms", -1); %! res = {" 68° 34' 12.0\" E ", " 180° 00' 00.0\" W ", " 110° 31' 55.2\" W ", ... %! " 85° 30' 00.0\" W ", " 80° 25' 30.0\" W ", " 4° 55' 58.8\" W ", ... %! " 0° 00' 00.0\" E ", " 3° 00' 37.4\" E ", " 90° 00' 00.4\" E ", ... %! " 180° 00' 00.0\" E ", " 126° 34' 30.0\" W "}; %! assert (str, res); %!test %! str = angltostr (deg2rad (ang), "pm", "radians", -6); %! res = {" +1.196772 R ", " -3.141593 R ", " -1.929147 R ", " -1.492257 R ", ... %! " -1.403681 R ", " -0.086097 R ", " +0.000000 R ", " +0.052541 R ", ... %! " +1.570798 R ", " +3.141593 R ", " -2.209151 R "}; %! assert (str, res); %!error angltostr ("oo"); %!error angltostr (2+3i); %!error angltostr (45, "ff"); %!error angltostr (33, 65); %!error angltostr (45, "ew", struct ()); %!error angltostr (88, "pm", "degs"); %!error angltostr (45, "ew", "radians", "acc"); %!error angltostr (45, "ew", "radians", 3+2i); %!error angltostr (45, "ns", "degs"); mapping-1.4.3/inst/PaxHeaders/extractfield.m0000644000000000000000000000006215005124246016042 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/extractfield.m0000644000175000017500000000664415005124246016370 0ustar00philipphilip## Copyright (C) 2014-2022 Carnë Draug ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or (at ## your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} extractfield (@var{s}, @var{field}) ## Extract field values from struct array. ## ## Concatenates all the values from the field member @var{field} in the ## structure array @var{s}. The values are all concatenated into a row ## vector of the same type as the values. ## ## @group ## @example ## s(1).field = 1:3; ## s(2).field = 4:9; ## extractfield (s, "field") ## @result{} ## [ 1 2 3 4 5 6 7 8 9 ] ## @end example ## @end group ## ## If any of the values is a string, or if the class is not the same for ## all the elements, a cell array with the intact elements is returned ## instead. ## ## @group ## @example ## s(1).field = 1:3; ## s(2).field = uint8 (4:6); ## extractfield (s, "field") ## @result{} ## [ 1 2 3 ] ## @result{} ## [ 4 5 6 ] ## @end example ## ## @example ## s(1).field = "text"; ## s(2).field = 1:3; ## extractfield (s, "field") ## @result{} ## text ## @result{} ## [ 1 2 3 ] ## @end example ## @end group ## ## @seealso{cell2mat, cellfun, getfield} ## @end deftypefn ## Author: Carnë Draug function vals = extractfield (s, name) if (nargin != 2) print_usage (); elseif (! isstruct (s)) error ("extractfield: S must be a struct"); elseif (! isfield (s, name)) error ("extractfield: NAME is a not a field of S"); endif vals = {s(:).(name)}; ## If none of them is char and they are all of the same class, ## get a vector out of it if (! any (cellfun ("isclass", vals, "char")) && all (cellfun ("isclass", vals, class (vals{1})))) ## matlab compatibility, all values in single row foo = @(x) vec (x, 2); vals = cell2mat (cellfun (foo, vals, "UniformOutput", false)); endif endfunction %!test %! a = {1:3, 4:6, [7:9]', 10:11, uint8(12:13), "text"}; %! s(1).a = a{1}; %! s(2).a = a{2}; %! assert (extractfield (s, "a"), 1:6); %! s(3).a = a{3}; %! assert (extractfield (s, "a"), 1:9); %! s(4).a = a{4}; %! assert (extractfield (s, "a"), 1:11); %! s(5).a = a{5}; %! assert (extractfield (s, "a"), a(1:5)); %! s(6).a = a{6}; %! assert (extractfield (s, "a"), a); ## we don't mess up when transposing complex numbers %!test %! s(1).a = [4 5]; %! s(2).a = [6i 7i 8]; %! assert (extractfield (s, "a"), [4 5 6i 7i 8]); %!test %! s(1).a = 0; %! s(2).a = false; %! assert (extractfield (s, "a"), {0, false}); ## check we don't mess up when there's other fields %!test %! s = struct ("a", mat2cell (1:10, 1, [3 3 4]), %! "b", mat2cell (11:20, 1, [5 2 3])); %! assert (extractfield (s, "a"), 1:10); %! assert (extractfield (s, "b"), 11:20); %!error extractfield (5, "name") %!error extractfield (struct ("name", 5), "not a name") mapping-1.4.3/inst/PaxHeaders/sm2km.m0000644000000000000000000000006215005124246014415 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/sm2km.m0000644000175000017500000000265415005124246014740 0ustar00philipphilip## Copyright (C) 2014-2022 Eugenio Gianniti ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or (at ## your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} sm2km (@var{sm}) ## Convert U.S. survey miles (statute miles) into kilometers. ## ## @seealso{km2nm, km2sm, nm2km, nm2sm, sm2nm} ## @end deftypefn ## Author: Eugenio Gianniti function km = sm2km (sm) if (nargin != 1) print_usage (); endif persistent ratio = unitsratio ("kilometer", "U.S. survey mile (statute mile)"); km = sm * ratio; endfunction %!test %! km = [2 6336 4.8326 6.437388874777749]; %! sm = [1.242739898989899 3937 3.002832417929293 4]; %! assert (sm2km (sm), km) %! km = reshape (km, [1 2 2]); %! sm = reshape (sm, [1 2 2]); %! assert (sm2km (sm), km) %!assert (sm2km (3937), 6336) mapping-1.4.3/inst/PaxHeaders/km2nm.m0000644000000000000000000000006215005124246014410 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/km2nm.m0000644000175000017500000000260015005124246014722 0ustar00philipphilip## Copyright (C) 2014-2022 Eugenio Gianniti ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or (at ## your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} km2nm (@var{km}) ## Convert kilometers into nautical miles. ## ## @seealso{km2sm, nm2km, nm2sm, sm2km, sm2nm} ## @end deftypefn ## Author: Eugenio Gianniti function nm = km2nm (km) if (nargin != 1) print_usage (); endif persistent ratio = unitsratio ("nautical mile", "kilometer"); nm = km * ratio; endfunction %!test %! km = [1.8520 3.7040 5.5560 7.4080 12.9640 14.8160]; %! nm = [1 2 3 4 7 8]; %! assert (km2nm (km), nm) %! km = reshape (km, [1 3 2]); %! nm = reshape (nm, [1 3 2]); %! assert (km2nm (km), nm) %!assert (km2nm (1.852), 1) mapping-1.4.3/inst/PaxHeaders/rasterread.m0000644000000000000000000000006215005124246015520 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/rasterread.m0000644000175000017500000000622715005124246016043 0ustar00philipphilip## Copyright (C) 2015-2022 Philip Nienhuis ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{bands}, @var{info}] =} rasterread (@var{fname}) ## Read a GIS raster file ## ## @var{fname} can be about any type of GIS raster file recognized by the ## GDAL library. For .adf files, either the name of the subdirectory ## containing the various component files, or the name of one of those ## component files can be specified. ## ## Output argument @var{bands} is a struct, or if multiple bands were read, ## a struct array, with data of each band: data, min, max, bbox, and ## (if present for the band) a GDAL colortable (see GDAL on-line ## reference). ## ## Output argument @var{binfo} contains various info of the raster file: ## overall bounding box, geotransformation, projection, size, nr. of columns ## and rows, datatype, nr. of bands. ## ## rasterread.m needs the GDAL library. ## ## @seealso{gdalread, gdalwrite} ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2015-10-15 function [bands, binfo] = rasterread (fname="") ## Checks if (! ischar (fname)) print_usage (); elseif (isempty (fname)) print_usage (); elseif (exist (fname) != 2) error ("rasterread: file '%s' not found\n", fname); endif bands = info = {}; ## Try to read data [status, binfo, bands] = gdalread (fname); if (! status) binfo.bbox = [Inf Inf; -Inf -Inf]; for ii=1:numel (bands) ## gdalread() rotates bands 90 degrees probably due to fortran_vec bands(ii).data = rot90 (bands(ii).data, 1); binfo.bbox(1, 1:2) = min (binfo.bbox(1, 1:2), bands(ii).bbox(1, 1:2)); binfo.bbox(2, 1:2) = max (binfo.bbox(2, 1:2), bands(ii).bbox(2, 1:2)); if (bands(ii).has_ndv) bands(ii).ndv = bands(ii).ndv_val; else bands(ii).ndv = []; endif if (! isempty (bands(ii).colortable) && all (abs (bands(ii).colortable(:, 4)) > 1e-10)) bands(ii).colortable(:, 1:3) = bands(ii).colortable(:, 1:3) ./ ... bands(ii).colortable(:, 4); endif endfor ## Remove fieldnames that are no longer needed dflds = setdiff (fieldnames (bands), {"data", "bbox", "min", "max", ... "ndv", "colortable"}); bands = rmfield (bands, dflds); ## Add file info to binfo binfo.Filename = canonicalize_file_name (fname); binfo.FileSize = stat (fname).size; binfo.FileModDate = strftime ("%d-%b-%y %H:%M:%S", localtime (stat (fname).mtime)); endif endfunction mapping-1.4.3/inst/PaxHeaders/meridianarc.m0000644000000000000000000000006215005124246015642 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/meridianarc.m0000644000175000017500000001024115005124246016154 0ustar00philipphilip## Copyright (C) 2019-2022 Philip Nienhuis ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or (at ## your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSEll. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{s} =} meridianarc (@var{phi}, @var{phi_2}) ## @deftypefnx {Function File} {@var{s} =} meridianarc (@var{phi}, @var{phi_2}, @var{spheroid}) ## @deftypefnx {Function File} {@var{s} =} meridianarc (@dots{}, @var{angleUnit}) ## Returns the meridian arc length given two latitudes @var{phi} and @var{phi_2}. ## ## @var{phi} and @var{phi_2} can be scalars, vectors or arrays of any desired ## size and dimension; but if any is non-scalar, the other must be scalar or ## have the exact same dimensions. For any @var{phi_2} larger than @var{phi} ## the output value will be negative. ## ## If no spheroid is given the default is wgs84. ## ## @var{angleUnit} can be 'degrees' or 'radians' (the latter is default). ## ## Examples ## Full options: ## @example ## s = meridianarc (0, 56, "int24", "degrees") ## => s = ## 6.2087e+06 ## @end example ## Short version: ## @example ## s = meridianarc (0, pi/4) ## => s = ## 4.9849e+06 ## @end example ## If want different units: ## @example ## s = meridianarc (0, 56, referenceEllipsoid ("int24", "km"), "degrees") ## => s = ## 6208.7 ## @end example ## @seealso{referenceEllipsoid} ## @end deftypefn ## Function supplied by anonymous contributor, see: ## https://savannah.gnu.org/patch/index.php?9720 function s = meridianarc (phi, phi_2, spheroid="", angleUnit="radians") persistent intv = "-pi/2, pi/2"; persistent degintv = "-90, 90"; if (nargin < 2) print_usage (); endif if (strncmpi (lower (angleUnit), "degrees", numel (angleUnit)) == 1) phi = deg2rad (phi); phi_2 = deg2rad (phi_2); intv = degintv; endif ## Check on identical input sizes or one scalar if (! isscalar (phi)) if (isscalar (phi_2)) phi_2 = phi_2 * ones (size (phi)); elseif (! numel (size (phi) == numel (size (phi_2))) || ... ! all (size(phi) == size (phi_2))) error ("meridianarc: both inputs must have same size and dimensions"); endif elseif (! isscalar (phi_2)) if (isscalar (phi)) phi = phi * ones (size (phi_2)); elseif (! numel (size (phi) == numel (size (phi_2))) || ... ! all (size(phi) == size (phi_2))) error ("meridianarc: both inputs must have same size and dimensions"); endif endif if (abs (phi) > pi / 2 || abs (phi_2) > pi / 2) error ("meridianarc: latitudes must lie in interval [%s]", intv); endif if (isempty (spheroid)) E = referenceEllipsoid ("wgs84"); else if (isnumeric (spheroid)) spheroid = num2str (spheroid); endif E = sph_chk (spheroid); endif ## From: Algorithms for global positioning. Kai Borre and Gilbert Strang pg 373 ## Note: Using integral instead of Taylor Expansion if (isstruct (spheroid)) E = spheroid; elseif (ischar (spheroid)) E = referenceEllipsoid (spheroid); else error ("meridianarc: spheroid must be a string or a stucture"); endif e_sq = E.Eccentricity ^ 2; F = @(x) ((1 - e_sq * sin(x) ^ 2) ^ (-3 / 2)); s = zeros (size (phi)); for ii=1:numel (phi) s(ii) = E.SemimajorAxis * (1 - e_sq) * quad ( F, phi(ii), phi_2(ii), 1.0e-12); end %for endfunction %!test %! s = meridianarc (0, 56, "int24", "degrees"); %! assert (s, 6208700.08662672, 1e-6) %!test %! s = meridianarc ([-1/120; 45-1/120; 89+119/120], [1/120; 45+1/120; 90], ... %! "int24", "degrees"); %! assert (s, [1842.92463205; 1852.25585828; 1861.66609497/2], 1e-6); %!error meridianarc (-2, 2) %!error meridianarc (-91, 91, "", "d") mapping-1.4.3/inst/PaxHeaders/dm2degrees.m0000644000000000000000000000006215005124246015405 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/dm2degrees.m0000644000175000017500000000537015005124246015726 0ustar00philipphilip## Copyright (C) 2014-2022 Carnë Draug ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or (at ## your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} dm2degrees (@var{dm}) ## Convert degrees, minutes, and seconds components into decimal degrees. ## ## @var{dm} must be a 2 column matrix with one row per angle, each ## column correspoding to its degrees (an integer), and minutes (a less ## than 60 value, possibly fractional) components. ## ## The sign of the angle must be defined on its first non-zero component only, ## i.e., if an angle is negative, the minutes component must be positive ## unless its degrees component is zero. ## ## @seealso{degrees2dm, degree2dms, dms2degrees} ## @end deftypefn ## Author: Carnë Draug function deg = dm2degrees (dm) if (nargin != 1) print_usage (); elseif (! isnumeric (dm) || ndims (dm) != 2 || columns (dm) != 2) error ("dm2degrees: DM must be a numeric matrix with 2 columns"); elseif (any (fix (dm(:,1)) != dm(:,1))) error ("dm2degrees: degrees component (first column) must be an integer"); elseif (any (dm(:,2) >= 60)) error ("dm2degrees: minutes component (second column) must be less than 60"); endif ## join the degrees and minutes parts adm = abs (dm); deg = sum ([adm(:,1) adm(:,2)/60], 2); ## change the sign if any part is negative and check that negative ## sign is present on the first non-zero part only negs = dm < 0; if (any (dm(:,1) != 0 & negs(:,2))) error ("dm2degrees: minutes must be positive if degree is non-zero"); endif deg(any (negs, 2)) *= -1; endfunction %!test %! deg = [10 10.5 -10.5 -0.5 0.5]'; %! dm = [ 10 0 %! 10 30 %! -10 30 %! 0 -30 %! 0 30]; %! for i = 1:rows (dm) %! assert (dm2degrees (dm(i,:)), deg(i)); %! endfor %! assert (dm2degrees (dm), deg); %! assert (dm2degrees (single (dm)), single (deg)); %!error dm2degrees ([5 60]) %!error dm2degrees ([5 61]) %!error <2 columns> dm2degrees ([5 50 3]) %!error dm2degrees ([5 -40]) %!error dm2degrees ([-5 -40]) %!error dm2degrees (rand (7, 2, 3)) mapping-1.4.3/inst/PaxHeaders/fromDegrees.m0000644000000000000000000000006215005124246015626 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/fromDegrees.m0000644000175000017500000000466115005124246016151 0ustar00philipphilip## Copyright (C) 2014-2022 Carnë Draug ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or (at ## your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{a1}, @var{a2}, @dots{}] =} fromDegrees (@var{toUnit}, @var{deg1}, @var{deg2}, @dots{}) ## Convert angles from radians. ## ## Converts any number of input arguments, @var{deg1}, @var{deg2}, @dots{} ## with angles in degrees, into @var{toUnit} which may be @qcode{"radians"} or ## @qcode{"degrees"}. ## ## @example ## @group ## [a1, a2] = fromDegrees ("radians", 180, [180 360]) ## @result{} ## [ 3.1416 ] ## @result{} ## [ 3.1416 6.2832 ] ## @end group ## @end example ## ## @seealso{deg2rad, fromRadians, toDegrees, toRadians, unitsratio} ## @end deftypefn ## Author: Carnë Draug function varargout = fromDegrees (toUnit, varargin) if (nargin < 1) print_usage (); endif valid_unit = validatestring (toUnit, {"radians", "degrees"}, "fromDegrees", "TOUNIT"); switch (valid_unit(1)) case {"r"} varargout = cellfun (@deg2rad, varargin, "UniformOutput", false); case {"d"} varargout = varargin; endswitch endfunction %!test %! rad{1} = pi; %! rad{2} = [pi 2*pi]; %! rad{3} = [0 pi; 2*pi 0]; %! deg{1} = 180; %! deg{2} = [180 360]; %! deg{3} = [0 180; 360 0]; %! for i=1:3 %! assert (fromDegrees ("degrees", deg{i}), deg{i}) %! assert (fromDegrees ("radians", deg{i}), rad{i}) %! endfor %! %! ## test multiple angles same time %! assert (nthargout (1:3, @fromDegrees, "radians", deg{:}), rad) %! assert (nthargout (1:2, @fromDegrees, "radians", deg{:}), rad(1:2)) %! %! ## test abbreviations of degrees %! assert (nthargout (1:3, @fromDegrees, "radian", deg{:}), rad) %! assert (nthargout (1:3, @fromDegrees, "rad", deg{:}), rad) %! assert (nthargout (1:3, @fromDegrees, "r", deg{:}), rad) %!error fromDegrees ("INVALID") mapping-1.4.3/inst/PaxHeaders/ned2geodetic.m0000644000000000000000000000006215005124246015720 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/ned2geodetic.m0000644000175000017500000001713215005124246016240 0ustar00philipphilip## Copyright (c) 2014-2022 Michael Hirsch, Ph.D. ## Copyright (c) 2013-2022 Felipe Geremia Nievinski ## Copyright (C) 2020-2022 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{lat}, @var{lon}, @var{alt} =} ned2geodetic (@var{n}, @var{e}, @var{d}, @var{lat0}, @var{lon0}, @var{alt0}) ## @deftypefnx {Function File} {@var{lat}, @var{lon}, @var{alt} =} ned2geodetic (@var{n}, @var{e}, @var{d}, @var{lat0}, @var{lon0}, @var{alt0}, @var{spheroid}) ## @deftypefnx {Function File} {@var{lat}, @var{lon}, @var{alt} =} ned2geodetic (@var{n}, @var{e}, @var{d}, @var{lat0}, @var{lon0}, @var{alt0}, @var{spheroid}, @var{angleUnit}) ## Convert local cartesian North, East, Down (NED) coordinates to geodetic ## coordinates. ## ## Inputs: ## @itemize ## @item ## @var{n}, @var{e}, @var{d}: look angles and distance to target point(s) ## (angle, angle, length). Can be scalars but vectors and nD arrays values ## are accepted if they have equal dimensions. ## ## @item ## @var{lat0}, @var{lon0}, @var{alt0}: ellipsoid geodetic coordinates of ## observer location (angle, angle, length). In case of multiple observer ## locations their numbers and dimensions should match those of the target ## points (i.e., one observer location for each target point). The length ## units of target point(s) and observer location(s) should match. ## ## @item ## @var{spheroid}: referenceEllipsoid parameter struct; default is wgs84. A ## string value or numerical EPSG code describing the spheroid is also ## accepted. ## ## @item ## @var{angleUnit}: string for angular units ('degrees' or 'radians', ## case-insensitive, just the first charachter will do). Default is 'degrees'. ## @end itemize ## ## Outputs: ## @itemize ## @item ## @var{lat}, @var{lon}, @var{alt}: geodetic coordinates of target points ## (angle, angle, length). ## ## Note: @var{alt} (height) is relative to the reference ellipsoid, not the ## geoid. Use e.g., egm96geoid to compute the height difference between the ## geoid and the WGS84 reference ellipsoid. ## @end itemize ## ## Lengh units are those of the invoked reference ellipsoid (see below). ## ## ned2geodetic.m is a wrapper for ned2ecef.m and ecef2geodetic.m ## ## Examples ## @example ## [lat, lon, alt] = ned2geodetic (286.84, 186.28, -939.69, 42, -82, 200) ## lat = 42.003 ## lon = -81.998 ## alt = 1139.7 ## @end example ## ## With radians: ## @example ## [lat, lon, alt] = ned2geodetic (286.84, 186.28, -939.69, pi/4, -pi/2, 200, ... ## "wgs84", "radians") ## lat = 0.78544 ## lon = -1.5708 ## alt = 1139.7 ## @end example ## ## @seealso{geodetic2ned, ned2aer, ned2ecef, ned2ecefv, referenceEllipsoid} ## @end deftypefn ## Function adapted by anonymous contributor, see: ## https://savannah.gnu.org/patch/index.php?9923 function [lat, lon, alt] = ned2geodetic (varargin) spheroid = ""; angleUnit = "degrees"; if (nargin < 6 || nargin > 8) print_usage(); elseif (nargin == 7) if (isnumeric (varargin{7})) ## EPSG spheroid code spheroid = varargin{7}; elseif (ischar (varargin{7})) if (! isempty (varargin{7}) && ismember (varargin{7}(1), {"r", "d"})) angleUnit = varargin{7}; else spheroid = varargin{7}; endif elseif (isstruct (varargin{7})) spheroid = varargin{7}; else error ("ned2geodetic: spheroid or angleUnit expected for arg. #7"); endif elseif (nargin == 8) spheroid = varargin{7}; angleUnit = varargin{8}; endif n = varargin{1}; e = varargin{2}; d = varargin{3}; lat0 = varargin{4}; lon0 = varargin{5}; alt0 = varargin{6}; if (! isnumeric (e) || ! isreal (e) || ... ! isnumeric (n) || ! isreal (n) || ... ! isnumeric (d) || ! isreal (d) ||... ! isnumeric (lat0) || ! isreal (lat0) || ... ! isnumeric (lon0) || ! isreal (lon0) || ... ! isnumeric (alt0) || ! isreal (alt0)) error ("ned2geodetic: numeric real values expected for first 6 inputs."); endif if (! all (size (e) == size (n)) || ... ! all (size (n) == size (d))) ... error ("ned2geodetic: non-matching dimensions of inputs."); endif if (! isscalar (lat0) || ! isscalar (lon0) || ! isscalar (alt0)) ## Check if for each test point a matching obsrver point is given if (! all (size (lat0) == size (e)) || ... ! all (size (lon0) == size (n)) || ... ! all (size (alt0) == size (d))) error (["ned2geodetic: non-matching dimensions of non-scalar observer ", ... "points and target points"]); endif endif if (isnumeric (spheroid)) spheroid = num2str (spheroid); endif E = sph_chk (spheroid); [x, y, z] = ned2ecef (n, e, d, lat0, lon0, alt0, E, angleUnit); [lat, lon, alt] = ecef2geodetic (E, x, y, z, angleUnit); endfunction %!test %! [lat, lon, alt] = ned2geodetic (286.84, 186.28, -939.69, 42, -82, 200); %! assert ([lat, lon, alt], [42.00258, -81.997752, 1139.69918], 10e-6); %!test %! [lat, lon, alt] = ned2geodetic (286.84, 186.28, -939.69, 0.733038285837618, -1.43116998663535, 200, "", "rad"); %! assert ([lat, lon, alt], [0.73308, -1.43113, 1139.69918], 10e-6); %!test %! [a, b, c] = ned2geodetic (-4556.3, -7134.8, -2852.4, 46.017, 7.750, 1673, 7030); %! assert ([a, b, c], [45.976000, 7.657999, 4531.009608], 1e-6); %!test %! [a, b, c] = ned2geodetic (1334.3, -2543.6, 359.65, 44.532, -72.782, 1699); %! assert ([a, b, c], [44.5440, -72.8140, 1339.9960], 1e-4); %!error ned2geodetic("s", 25, 1e3, 0, 0, 0) %!error ned2geodetic(3i, 25, 1e3, 0, 0, 0) %!error ned2geodetic(33, "s", 1e3, 0, 0, 0) %!error ned2geodetic(33, 3i, 1e3, 0, 0, 0) %!error ned2geodetic(33, 25, "s", 0, 0, 0) %!error ned2geodetic(33, 25, 3i, 0, 0, 0) %!error ned2geodetic(33, 25, 1e3, "s", 0, 0) %!error ned2geodetic(33, 25, 1e3, 3i, 0, 0) %!error ned2geodetic(33, 25, 1e3, 0, "s", 0) %!error ned2geodetic(33, 25, 1e3, 0, 3i, 0) %!error ned2geodetic(33, 25, 1e3, 0, 0, "s") %!error ned2geodetic(33, 25, 1e3, 0, 0, 3i) %!error ned2geodetic ([1 1], [2 2]', [3 3], 4, 5, 6) %!error ned2geodetic ([1 1], [2 2], [33], 4, 5, 6) %!error ned2geodetic ([1 1], [2 2], [3 3], [4 4], 5, 6) %!error ned2geodetic ([1 1], [2 2], [3 3], 4, [5 5], 6) %!error ned2geodetic ([1 1], [2 2], [3 3], [4; 4], [5; 5], [6; 6]) mapping-1.4.3/inst/PaxHeaders/minaxis.m0000644000000000000000000000006215005124246015034 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/minaxis.m0000644000175000017500000000533015005124246015351 0ustar00philipphilip## Copyright (C) 2018-2022 Philip Nienhuis ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{semiminoraxis} =} minaxis (@var{semimajoraxis}, @var{ecc}) ## Return the semiminor axis given the semimmajor axis (a) and eccentricity (ecc). ## ## Examples ## ## Scalar input: ## @example ## earth_a = 6378137; %m ## earth_ecc = 0.081819221456; ## earth_b = minaxis (earth_a, earth_ecc) ## => earth_b = ## 6.3568e+06 ## @end example ## ## Vector input: ## @example ## planets_a = [ 6378137 ; 66854000 ]; ## planets_ecc = [ 0.081819221456 ; 0.3543164 ]; ## planets_b = minaxis (planets_a , planets_ecc) ## => planets_b = ## 6.3568e+06 ## 6.2517e+07 ## @end example ## ## @seealso{majaxis} ## @end deftypefn ## Function supplied by anonymous contributor, see: ## https://savannah.gnu.org/patch/index.php?9566 ## For background see https://en.wikipedia.org/wiki/Flattening function b = minaxis (a, ecc) if (nargin < 2) print_usage (); end if (! isnumeric (a) || ! isreal (a) || ! isnumeric (ecc) || ! isreal (ecc)) error ("minaxis : numeric input expected"); elseif (any (ecc < 0) || any (ecc > 1)) error ("minaxis: eccentricity must lie in interval [0..1]") elseif ((length (a) != 1 && length(ecc) != 1) && ((size (a) != size (ecc)))) error ("minaxis: vectors must be the same size") else b = a .* sqrt ( 1 - ecc .^ 2 ); end endfunction %!test %! %! earth_a = 6378137; %! earth_ecc = 0.081819221456; %! assert ( minaxis (earth_a, earth_ecc), 6356752.2982157, 10e-8 ) %! planets_a = [ 6378137 ; 66854000 ]; %! planets_ecc = [ 0.081819221456 ; 0.3543164 ]; %! assert ( minaxis (planets_a, planets_ecc), [ 6356752.29821572 ; 62516886.8951319 ], 10e-8 ) %!error minaxis (0.5, "ecc") %!error minaxis (0.5, 0.3 + 0.5i) %!error minaxis ("a", 0.5) %!error minaxis (0.3 + 0.5i , 0.5) %!error minaxis ( [ 6378137 ; 66854000 ], [ 0.081819221456 ; 0.3543164 ]') %!error minaxis ([10; 10; 10], [0.5; 0; -0.5]) mapping-1.4.3/inst/PaxHeaders/utmzone.m0000644000000000000000000000006215005124246015065 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/utmzone.m0000644000175000017500000001211315005124246015377 0ustar00philipphilip## Copyright (C) 2019-2022 Philip Nienhuis ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or (at ## your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSEll. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{zone} =} utmzone (@var{lat} , @var{long}) ## @deftypefnx {Function File} {@var{latlon} =} utmzone (@var{zone}) ## @deftypefnx {Function File} {@var{lat}, @var{long} =} utmzone (@var{zone}) ## Returns the zone given a latitude and longitude, or the latitude and ## longitude ranges given a zone. ## ## Examples: ## ## @example ## utmzone (43, -79) ## => ans = ## 17T ## @end example ## ## Can also handle the special zones of Norway ## ## @example ## utmzone (60, 5) ## => ans = ## 32V ## @end example ## ## For zones: ## ## @example ## utmzone ("17T") ## => ans = ## 40 48 ## -84 -78 ## @end example ## ## @example ## [lat, lon] = utmzone ("17T") ## => ## lat = ## 40 48 ## lon = ## -84 -78 ## @end example ## ## @end deftypefn ## Function supplied by anonymous contributor, see: ## https://savannah.gnu.org/patch/index.php?9756 function [zone, z2] = utmzone (lat, long) ## Since there is no I or O, the last 4 are special cases alphabet = ("CDEFGHJKLMNPQRSTUVWXABYZ"); if (nargin < 2) if (ischar (lat) && numel (lat) > 1) num = sscanf (lat, "%f"); if (num < 1) error ("utmzone: positive number expecte for zone"); endif let = find (alphabet == upper (lat(end))); if (isempty (let)) error ("utmzone: incorrect or no letter specified"); endif switch upper (lat(end)) case "A" lat = [-80 -90]; long = [-180 0]; zone = [lat; long]; case "B" lat = [-80 -90]; long = [0 180]; zone = [lat; long]; case "Y" lat = [84 90]; long = [-180 0]; zone = [lat; long]; case "Z" lat = [84 90]; long = [0 180]; zone = [lat; long]; case "X" lat = [72 84]; switch num case 31 long = [0 9]; case 33 long = [9 21]; case 35 long = [21 33]; case 37 long = [33 42]; case {32, 34, 36} error ("utmzone: zone %2iX does not exist", num); otherwise long = [(num - 1) * 6 - 180, (num * 6 - 180)]; endswitch zone = [lat; long]; case "V" lat = [56 64]; switch num case 31 long = [0 3]; case 32 long = [3 12]; otherwise long = [(num - 1) * 6 - 180, (num * 6 - 180)]; endswitch zone = [lat; long]; otherwise lat = [(let - 1) * 8 - 80, (let * 8) - 80 ]; long = [(num - 1) * 6 - 180, (num * 6 - 180)]; zone = [lat; long]; endswitch endif if (nargout ==2) zone = lat; z2 = long; endif elseif (isnumeric (lat) && isreal (lat) && isnumeric (long) && isreal (long)) lat = mean (lat); long = mean (long); if (lat <= -80) if (long < 0) zone = "A"; else zone = "B"; endif elseif (lat >= 84) if long < 0 zone = "Y"; else zone = "Z"; endif elseif (lat >= 72 && lat < 84) if (long >= 0 && long < 9) zone = "31X"; elseif (long >= 9 && long < 21) zone = "33X"; elseif (long >= 21 && long < 33) zone = "35X"; elseif (long >= 33 && long < 42) zone = "37X"; else zone = zone (lat, long); endif elseif (lat >= 56 && lat < 64) if (long >= 0 && long < 3) zone = "31V"; elseif (long >= 3 && long < 12) zone = "32V"; endif else zone = zone (lat, long); endif else error ("utmzone: numeric input expected for LAT en LON"); endif endfunction function z = zone (lat, long) alphabet = ("CDEFGHJKLMNPQRSTUVWX"); num = floor ((long + 180) / 6) + 1; idx = -80; ind = 0; while (lat > idx) idx = idx + 8; ind = ind + 1; endwhile let = alphabet (ind); z = strcat (num2str (num), let); endfunction %!test %! lat = 43; ## From Wiki %! long = -79; %! assert (utmzone (lat, long), "17T") %!assert (utmzone ("17T"), [40, 48;-84, -78]) %!assert (utmzone (60, 5), "32V") ## For Bergen Norway %!assert (utmzone ("32V"), [56, 64;3, 12]) %!error utmzone ("32X") %!error utmzone ("31I") %!error utmzone ("31O") mapping-1.4.3/inst/PaxHeaders/iso2geo.m0000644000000000000000000000006215005124246014733 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/iso2geo.m0000644000175000017500000000536315005124246015256 0ustar00philipphilip## Copyright (C) 2022 The Octave Project Developers ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . ## -*- texinfo -*- ## @deftypefn {} {@var{psi} =} iso2geo (@var{phi}) ## @deftypefnx {} {@var{psi} =} iso2geo (@var{phi}, @var{spheroid}) ## @deftypefnx {} {@var{psi} =} iso2geo (@var{phi}, @var{spheroid}, @var{angleUnit}) ## Returns the isometric latitude given geodetic latitude @var{phi} ## ## Input ## @itemize ## @item ## @var{phi}: the geodetic latitude(s). Can be a scalar, vector or ND-array. ## @end itemize ## ## @itemize ## @item ## (optional) @var{spheroid}: referenceEllipsoid. For admissible values see ## `referenceEllipsoid`. The default value is 'WGS84'. ## ## @item ## (optional) @var{angleUnit}: string for angular units ('degrees' or 'radians', ## case-insensitive, just the first charachter will do). Default is 'degrees'. ## @end itemize ## ## Output ## @itemize ## @item ## @var{psi}: the isometric latitude(s), same shape as @var{phi}. ## @end itemize ## ## Example ## @example ## iso2geo (45) ## ans = 41.170 ## @end example ## @seealso{geo2auth, geo2con, geo2iso, geo2rect} ## @end deftypefn function [phi] = iso2geo (psi, spheroid = "", angleUnit = "degrees") if (nargin < 1 || nargin > 3) print_usage(); endif if (! isnumeric (psi) || ! isreal (psi)) error ("iso2geo: numeric input expected"); endif E = sph_chk(spheroid); if (! ischar (angleUnit)) error ("iso2geo: character value expected for 'angleUnit'"); elseif (strncmpi (angleUnit, "degrees", min (length (angleUnit), 7))) psi = deg2rad (psi); elseif (! strncmpi (angleUnit, "radians", min (length (angleUnit), 7))) error ("iso2geo: illegal input for 'angleUnit'"); endif ## From Snyder's "Map Projections-A Working Manual" [pg 15]. chi = 2 * atan (exp (psi)) - pi / 2; phi = con2geo (chi, E, "radians"); if (strncmpi (angleUnit, "degrees", length (angleUnit))) phi = rad2deg (phi); endif endfunction %!test %! psi = iso2geo (50.227465817); %! assert (psi, 45, 1e-6) %!test %! assert(iso2geo (geo2iso ([-90 : 10: 0; 0 : 10 : 90]), "wgs84"), ... %! [-90 : 10: 0; 0 : 10 : 90], 1e-8); %!error iso2geo ("s") %!error iso2geo (5i) mapping-1.4.3/inst/PaxHeaders/kmlread.m0000644000000000000000000000006215005124246015003 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/kmlread.m0000644000175000017500000002054715005124246015327 0ustar00philipphilip## Copyright (C) 2018-2022 Philip Nienhuis ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{kml} =} kmlread (@var{fname}) ## (EXPERIMENTAL) Read a Google kml file and return its contents in a struct. ## ## @var{name} is the name of a .kml file. ## Currently kmlread can read Point, LineString, Polygon, Track and Multitrack ## entries. ## ## @var{kml} is a struct with fields Type, Lat, Lon, Ele, Time and Name. If ## the .kml file contained LineStrings and/or Polygons also field BoundingBox ## is present containing suitable values for the relevant items. ## ## @seealso{kmzread} ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2018-05-03 function outp = kmlread (fname) fid = fopen (fname, "r"); if (fid > 0) xml = fread (fid, Inf, "*char")'; fclose (fid); else error ("kmlread: couldn't read %s", fname); endif outp = repmat (struct ("Type", "-", ... "Lat", [], ... "Lon", [], ... "Ele", [], ... "Time", [], ... "Name", "-"), 0, 1); ## Points is = 1; ipt = 0; while (is > 0) [pnt, il, is] = getxmlnode (xml, "Point", is, 1); if (is > 0) outp(end+1).Type = "Point"; ++ipt; pnam = regexp (xml(max (1, il - 1000):il+7), ... '.*?(.+?).*? 0) [lin, il, is] = getxmlnode (xml, "LineString", is, 1); if (is > 0) outp(end+1).Type = "Line"; ++iln; lnam = regexp (xml(max (1, il - 1000):il+12), ... '.*?(.+?).*? 2) outp(end).Ele = xyz(:, 3); outp(end).BoundingBox = [outp(end).BoundingBox; min(outp(end).Ele), max(outp(end).Ele)]; else outp(end).BoundingBox = [outp(end).BoundingBox; NaN, NaN]; endif endif endwhile ## Polygons is = 1; ip = 0; while (is > 0) [pol, il, is] = getxmlnode (xml, "Polygon", is, 1); if (is > 0) outp(end+1).Type = "Polygon"; ++ip; pnam = regexp (xml(max (1, il - 1000):il+12), ... '.*?(.+?).*? 0) [ring, ~, ir] = getxmlnode (pol, "innerBoundaryIs", ir); if (ir > 0) coords = strrep (getxmlnode (ring, "coordinates", 1, 1), ",", " "); xyz = reshape (sscanf (coords, "%f", Inf)', 3, [])'; ## FIXME check on CW outp(end).Lon = [outp(end).Lon; NaN; xyz(:, 1)]; outp(end).Lat = [outp(end).Lat; NaN; xyz(:, 2)]; outp(end).Ele = [outp(end).Ele; NaN; xyz(:, 3)]; endif endwhile outp(end).BoundingBox = [min(outp(end).Lon), max(outp(end).Lon); ... min(outp(end).Lat), max(outp(end).Lat); ... min(outp(end).Ele), max(outp(end).Ele)]; endif endwhile ## Tracks and MultiTracks ptrnT = '(.*?)'; is = em = 1; it = 0; while (is > 0) if (em <= is) ## Try to get extent of multiTrack node [mtrk, ~, em] = getxmlnode (xml, "gx:MultiTrack", is, 1); if (em > 0) ## Get specific attributes for this Multitrack mtid = getxmlattv (mtrk, "id"); intpm = str2double (getxmlnode (mtrk, "gx:interpolate", 10, 1)); ## MultiTrack; start new struct item for next tracks outp(end+1).Type = "Track"; ++it; if (isempty (mtid)) outp(end).Name = ["Track #" num2str(it)]; else outp(end).Name = mtid; endif endif endif [trk, ~, is] = getxmlnode (xml, "gx:Track", is, 1); if (is > 0) if (! em) ## Separate track; start new struct item outp(end+1).Type = "Track"; ++it; tnam = getxmlattv (trk, "id"); if (isempty (tnam)) outp(end).Name = ["Track #" num2str(it)]; else outp(end) = tnam; endif outp(end).BoundingBox = [min(outp(end).Lon), max(outp(end).Lon); ... min(outp(end).Lat), max(outp(end).Lat); ... min(outp(end).Ele), max(outp(end).Ele)]; endif times = cell2mat (regexp (trk, ptrnT, "tokens")); ltime = cellfun ("numel", times); if (any (ltime < 20)) ## Year resolution times(ltime == 4) = ... cellfun (@(x) [x "-00-00T00:00:00Z"], times(ltime == 4), "uni", 0); ## Month resolution times(ltime == 7) = ... cellfun (@(x) [x "-00T00:00:00Z"], times(ltime == 7), "uni", 0); ## Day resolution times(ltime == 10) = ... cellfun (@(x) [x "T00:00:00Z"], times(ltime == 10), "uni", 0); endif times = datenum (times, "yyyy-mm-ddTHH:MM:SSZ"); ptrnP = '(.+?) (.+?) (.+?)'; xyz = reshape (str2double (cell2mat (regexp (trk, ptrnP, "tokens"))), 3, [])'; if (isempty (outp(end).Lat)) outp(end).Lon = xyz(:, 1); outp(end).Lat = xyz(:, 2); outp(end).Ele = xyz(:, 3); if (! isempty (times)) outp(end).Time = times; endif elseif (intpm) outp(end).Lon = [outp(end).Lon; xyz(:, 1)]; outp(end).Lat = [outp(end).Lat; xyz(:, 2)]; outp(end).Ele = [outp(end).Ele; xyz(:, 3)]; if (! isempty (times)) outp(end).Time = [outp(end).Time; times]; endif else outp(end).Lon = [outp(end).Lon; NaN; xyz(:, 1)]; outp(end).Lat = [outp(end).Lat; NaN; xyz(:, 2)]; outp(end).Ele = [outp(end).Ele; NaN; xyz(:, 3)]; if (! isempty (times)) outp(end).Time = [outp(end).Time; NaN; times]; endif endif outp(end).BoundingBox = [min(outp(end).Lon), max(outp(end).Lon); ... min(outp(end).Lat), max(outp(end).Lat); ... min(outp(end).Ele), max(outp(end).Ele)]; endif endwhile endfunction mapping-1.4.3/inst/PaxHeaders/shapeinfo.m0000644000000000000000000000006215005124246015340 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/shapeinfo.m0000644000175000017500000001321515005124246015656 0ustar00philipphilip## Copyright (C) 2014-2022 Philip Nienhuis ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} [ @var{infs} ] = shapeinfo (@var{fname}) ## Returns a struct with info on shapefile @var{fname}. ## ## Input: ## @table @code ## @item @var{fname} ## (character string). Does not need to have a .shp suffix. ## @end table ## ## Output: a struct with fields: ## ## @table @code ## @item Filename ## Contains the filename of the shapefile. ## ## @item ShapeType ## The type of shapefile. ## ## @item ShapeTypeName ## The name of the shape type. ## ## @item BoundingBox ## The minimum and maximum X and Y coordinates of all items in the shapefile in ## a 2 X 2 array, upper rox min and min Y, lower row max X and max Y. ## ## @item NumFeatures ## The number of features (items, records) in the shapefile. ## ## @item Attributes ## A structure with fields Name and Type (containng the names and types of all ## attributes in the shapefile). Type can be Numeric, Character or Data. ## @end table ## ## @seealso{geoshow, mapshow, shapedraw, shaperead, shapewrite} ## @end deftypefn ## Author: Philip Nienhuis char"); until (ftell (fidp) > flngt - 3); ## i.e., within last ## file byte printf (" \n"); ## Wipe "Counting.." else ## shx file found; no counting required fseek (fidx, 24, "bof"); fxlng = fread (fidx, 1, "int32", 72, "ieee-be"); recn = (fxlng - 50) / 4; fclose (fidx); endif fclose (fidp); finfo = dir (fname); ## Return info infs.NumFeatures = recn; infs.FileSize = finfo.bytes; infs.LastModified = datestr (finfo.datenum, 0); ## ====================== 3. .dbf ====================== ## Check if dbfread is available if (isempty (which ("dbfread"))) printf ("shaperead: dbfread function not found. No attributes will be added.\n"); printf (" (io package installed and loaded?)\n"); else ## Try to read the .dbf file try [~, B] = dbfread ([bname ".dbf"], 0); infs.Attributes.Name = {B.data.fldnam}; types = {B.data.fldtyp}; types = strrep (types, "N", "Numeric"); types = strrep (types, "C", "Character"); types = strrep (types, "D", "Date"); types = strrep (types, "F", "Floating"); ## FIXME dbase also has type "Logical" infs.Attributes.Type = types; catch printf ("shaperead: file %s couldn't be opened;\n", [ bname ".dbf" ]); printf (" no attributes appended\n"); end_try_catch endif endfunction mapping-1.4.3/inst/PaxHeaders/meridianfwd.m0000644000000000000000000000006215005124246015655 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/meridianfwd.m0000644000175000017500000000423415005124246016174 0ustar00philipphilip## Copyright (C) 2022 The Octave Project Developers ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . ## -*- texinfo -*- ## @deftypefn {} {@var{lat2} =} meridianfwd (@var{lat}, @var{s}) ## @deftypefnx {} {@var{lat2} =} meridianfwd (@var{lat}, @var{s}, @var{spheroid}) ## @deftypefnx {} {@var{lat2} =} meridianfwd (@var{lat}, @var{s}, @var{spheroid}, @var{angleUnit}) ## Retuns the new latitude given a starting latitude and distance travelled ## along a meridian. ## ## Inputs ## ## @itemize ## @item ## @var{lat1}: the starting latitude. ## ## @item ## @var{s} the distance travelled. The units are based on the ellipsoid. ## The default is in meters but should match that of the ellipsoid (if any). ## ## @item ## (optional) @var{spheroid}: referenceEllipsoid (parameter struct, name or ## code): the default is 'wgs84'. ## ## @item ## (optional) @var{angleUnit}: string for angular units ('degrees' or 'radians', ## case-insensitive, just the first character will do). Default is 'radians'. ## ## Output ## @item ## @var{lat2}: the final latitude after travelling a distance of @var{s} ## @end itemize ## ## Example ## @example ## lat = meridianfwd (40, 1e6) ## lat = 48.983 ## @end example ## ## @seealso{meridianarc, geodeticfwd} ## @end deftypefn function [lat2] = meridianfwd (lat, s, spheroid = "wgs84", angleUnit = "radians") if (nargin < 2 || nargin > 4) print_usage(); endif lat2 = geodeticfwd (lat, 0, s, 0, spheroid, angleUnit, "length"); endfunction %!test %! a = rad2deg (meridianfwd (-pi/4, [60 120] * 45 * 1846.2756967249574, 'wgs84')); %! assert (a, [0, 45], 5e-7); mapping-1.4.3/inst/PaxHeaders/wrapTo180.m0000644000000000000000000000006215005124246015071 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/wrapTo180.m0000644000175000017500000000407115005124246015407 0ustar00philipphilip## Copyright (C) 2015-2022 Oscar Monerris Belda ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{xwrap} =} wrapTo180 (@var{x}) ## ## Wraps X into the [-180 to 180] interval. ## ## @var{x}: angle(s) in degrees (single value, vector or ND-matrix). ## ## @var{xwrap}: output value(s) in the range [-180 .. 180] degrees. ## The interval [-180 .. 180] is a closed interval: values equal to ## negative odd multiples of -180 are mapped to -180, values equal ## to an odd multiple of 180 are mapped to 180. ## ## @example ## wrapTo180 ([-181, -180, -50; 180, 200, 460]) ## ans = ## 179 -180 -50 ## 180 -160 100 ## @end example ## ## @seealso{unwrap, wrapToPi, wrapTo2Pi} ## @end deftypefn function xwrap = wrapTo180 (x) xwrap = rem (x, 360); idx = find (abs (xwrap) > 180); xwrap(idx) -= 360 * sign (xwrap(idx)); endfunction %!test %! x = -800:0.1:800; %! xw = wrapTo180 (x); %! assert (sind (x), sind (xw), 16 * eps) %! assert (cosd (x), cosd (xw), 16 * eps) %! assert (! any (xw < -180)) %! assert (! any (xw > 180)) %!test %! c = [-721.1, -718.9, -481.3, -479.99, -361, -359, -200, -180-(1e-14), -180, ... %! -180-(2e-14), -160, -eps, 0, eps, 160, 180, 180+(1e-14), 180+(2e-14), 200]; %! assert (wrapTo180 (c), [-1.10, 1.10, -121.30, -119.99, -1.0, 1.0, 160.0, ... %! -180.0, -180.0, 180.0, -160.0, -0.0, 0.0, 0.0, ... %! 160.0, 180.0, 180.0, -180.0, -160.0], 1e-13); mapping-1.4.3/inst/PaxHeaders/geo2rect.m0000644000000000000000000000006215005124246015076 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/geo2rect.m0000644000175000017500000000600115005124246015407 0ustar00philipphilip## Copyright (C) 2022 The Octave Project Developers ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . ## -*- texinfo -*- ## @deftypefn {} {@var{mu} =} geo2rect (@var{phi}) ## @deftypefnx {} {@var{mu} =} geo2rect (@var{phi}, @var{spheroid}) ## @deftypefnx {} {@var{mu} =} geo2rect (@var{phi}, @var{spheroid}, @var{angleUnit}) ## Returns the rectifying latitude given geodetic latitude @var{phi} ## ## Input ## @itemize ## @item ## @var{phi}: the geodetic latitude ## @end itemize ## ## @itemize ## @item ## (optional) @var{spheroid}: referenceEllipsoid name, EPSG code, or parameter ## struct: default is wgs84. ## ## @item ## (optional) @var{angleUnit}: string for angular units ('degrees' or 'radians', ## case-insensitive, just the first character will do). Default is 'degrees'. ## @end itemize ## ## Output ## @itemize ## @item ## @var{mu}: the rectifying latitude ## @end itemize ## ## Example ## @example ## geo2rect(45) ## ans = 44.856 ## @end example ## @seealso{geo2auth, geo2con, geo2iso} ## @end deftypefn function [mu] = geo2rect (phi, spheroid ="", angleUnit = "degrees") if (nargin < 1 || nargin > 3) print_usage(); endif if (! isnumeric (phi) || ! isreal (phi)) error ("geo2rect: numeric input expected"); endif if (isempty (spheroid)) E = referenceEllipsoid ("wgs84"); else if (isnumeric (spheroid)) spheroid = num2str (spheroid); endif E = sph_chk (spheroid); endif if (! ischar (angleUnit)) error ("geo2rect: character value expected for 'angleUnit'"); elseif (strncmpi (angleUnit, "degrees", min (length (angleUnit), 7))) ## Latitude must be within [-90 ... 90] if (any (abs (phi) > 90)) error ("geo2rect: azimuth value(s) out of acceptable range [-90, 90]") endif phi = deg2rad (phi); elseif (strncmpi (angleUnit, "radians", min (length (angleUnit), 7))) ## Latitude must be within [-pi/2 ... pi/2] if (any (abs (phi) > pi / 2)) error("geo2rect: azimuth value(s) out of acceptable range (-pi/2, pi/2)") endif else error ("geo2rect: illegal input for 'angleUnit'"); endif m = meridianarc (0, phi, E); m_p = meridianarc (0, pi / 2, E); mu = pi / 2 .* m ./ m_p; if (strncmpi (angleUnit, "degrees", length (angleUnit))) mu = rad2deg (mu); endif endfunction %!test %! mu = geo2rect (45); %! Z = degrees2dm(mu - 45); %! assert (Z(:,2), -8.65908066558504, 1e-6); %!error geo2rect ("s") %!error geo2rect (5i) mapping-1.4.3/inst/PaxHeaders/geo2iso.m0000644000000000000000000000006215005124246014733 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/geo2iso.m0000644000175000017500000000710715005124246015254 0ustar00philipphilip## Copyright (C) 2022 The Octave Project Developers ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . ## -*- texinfo -*- ## @deftypefn {} {@var{psi} =} geo2iso (@var{phi}) ## @deftypefnx {} {@var{psi} =} geo2iso (@var{phi}, @var{spheroid}) ## @deftypefnx {} {@var{psi} =} geo2iso (@var{phi}, @var{spheroid}, @var{angleUnit}) ## Return the isometric latitude given geodetic latitude @var{phi}. ## ## Input ## @itemize ## @item ## @var{phi}: the geodetic latitude. Can be a scalar value, a vector or an ## ND-array. ## @end itemize ## ## @itemize ## @item ## (optional) @var{spheroid}: referenceEllipsoid. For admissible values see ## `referenceEllipsoid.m`. The default ellipsoid is WGS84. ## is wgs84. ## ## @item ## (optional) @var{angleUnit}: string for angular units ('degrees' or 'radians', ## case-insensitive, just the first character will do). Default is 'degrees'. ## @end itemize ## ## Output ## @itemize ## @item ## @var{psi}: the isometric latitude(s), same shape as @var{phi}. ## @end itemize ## ## Example ## @example ## geo2iso (45) ## ans = 50.227 ## @end example ## @seealso{geo2auth, geo2con, geo2rect, iso2geo} ## @end deftypefn function [psi] = geo2iso (phi, spheroid = "", angleUnit = "degrees") if (nargin < 1 || nargin > 3) print_usage(); endif if (! isnumeric (phi) || ! isreal (phi)) error ("geo2iso: numeric input expected"); endif E = sph_chk (spheroid); if (! ischar (angleUnit)) error ("geo2iso: character value expected for 'angleUnit'"); elseif (strncmpi (angleUnit, "degrees", min (length (angleUnit), 7))) ## Latitude must be within [-90 ... 90] if (any (abs (phi) > 90)) error ("geo2iso: azimuth value(s) out of acceptable range [-90, 90]") endif phi = deg2rad (phi); elseif (strncmpi (angleUnit, "radians", min (length (angleUnit), 7))) ## Latitude must be within [-pi/2 ... pi/2] if (any (abs (phi) > pi / 2)) error("geo2iso: azimuth value(s) out of acceptable range (-pi/2, pi/2)") endif else error ("geo2iso: illegal input for 'angleUnit'"); endif ## Some previously tried solutions: ## https://en.wikipedia.org/wiki/Latitude#Isometric_latitude ## ecc = E.Eccentricity; ## psi = asinh (tan (phi)) - ecc .* atanh (ecc .* sin (phi)); ## From Snyder's "Map Projections - A Working Manual" [pg 15]. Eq (3-7) ## psi = log(tan(pi/4+phi/2)*((1-ecc.*sin(phi))/(1+ecc.*sin(phi)))^(ecc/2)); ## From Snyder's "Map Projections - A Working Manual" [pg 15]. Eq (3-8) chi = geo2con (phi, E, "radians"); psi = log (tan (pi / 4 + chi / 2)); psi(psi < -5.24) = -Inf; psi(psi > 5.24) = Inf; if (strncmpi (angleUnit, "degrees", length (angleUnit))) psi = rad2deg (psi); endif endfunction %!test %! psi = geo2iso (45); %! assert (psi, 50.227465817, 1e-6) %!test %! psi = geo2iso ([-90 90]); %! assert (psi, [-Inf Inf]) %!test %! chi = geo2iso (iso2geo ([-90 : 10: 0; 0 : 10 : 90]), "wgs84"); %! assert (chi, [-90 : 10: 0; 0 : 10 : 90], 1e-6); %!error geo2iso ("s") %!error geo2iso (5i) mapping-1.4.3/inst/PaxHeaders/parametricLatitude.m0000644000000000000000000000006215005124246017207 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/parametricLatitude.m0000644000175000017500000000676415005124246017540 0ustar00philipphilip## Copyright (C) 2018-2022 Philip Nienhuis ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{beta} =} parametricLatitude (@var{phi}, @var{flattening}) ## @deftypefnx {Function File} {@var{beta} =} parametricLatitude (@var{phi}, @var{flattening}, @var{angleUnit}) ## Returns parametric latitude given geodetic latitude (phi) and flattening. ## ## The parametric latitude @var{beta} is also known as a reduced latitude. ## The default input and output is in degrees; use optional third parameter ## @var{angleUnit} for radians. @var{phi} can be a scalar, vector, matrix ## or any ND array. @var{flattening} must be a scalar value in the interval ## [0..1). ## ## Examples: ## Scalar input: ## @example ## beta = parametricLatitude (45, 0.0033528) ## => beta = ## 44.904 ## @end example ## ## Also can use radians: ## @example ## beta = parametricLatitude (pi/4, 0.0033528, "radians") ## => beta = ## 0.78372 ## @end example ## ## Vector Input: ## @example ## phi = 35:5:45; ## beta = parametricLatitude (phi, 0.0033528) ## => beta = ## 34.91 39.905 44.904 ## @end example ## @seealso{geocentricLatitude , geodeticLatitudeFromGeocentric , geodeticLatitudeFromParametric} ## @end deftypefn ## Function supplied by anonymous contributor, see: ## https://savannah.gnu.org/patch/index.php?9640 function beta = parametricLatitude (phi, flattening, angleUnit="degrees") if (nargin < 2) print_usage (); endif if (! isnumeric (phi) || ! isreal (phi) || ... ! isnumeric (flattening) || ! isreal (flattening)) error ("parametricLatitude : numeric input expected"); elseif (! isscalar (flattening)) error ("parametricLatitude: scalar value expected for flattening"); elseif (flattening < 0 || flattening >= 1) error ("parametricLatitude: flattening must lie in the real interval [0..1)" ); elseif (! ischar (angleUnit) ||! ismember (lower (angleUnit(1)), {"d", "r"})) error ("parametricLatitude: angleUnit should be one of 'degrees' or 'radians'"); endif if (strncmpi (angleUnit, "r", 1) == 1) ## From: Algorithms for global positioning. Kai Borre and Gilbert Strang pg 371 beta = atan ((1 - flattening) * tan (phi)); else beta = atand ((1 - flattening) * tand (phi)); end endfunction %!test %! earth_flattening = 0.0033528 ; %! assert (parametricLatitude (45, earth_flattening), 44.903787, 10e-6) %! assert (parametricLatitude (pi/4, earth_flattening, 'radians'), 0.78372, 10e-6) %!error parametricLatitude (0.5, "flat") %!error parametricLatitude (0.5, 5i) %!error parametricLatitude ("phi", 0.0033528) %!error parametricLatitude (5i, 0.0033528 ) %!error parametricLatitude ([45 50], [0.7 0.8]) %!error parametricLatitude (45, 1) %!error parametricLatitude (45, 0.0033528, "km") mapping-1.4.3/inst/PaxHeaders/PKG_ADD0000644000000000000000000000006215005124246014222 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/PKG_ADD0000644000175000017500000000002515005124246014533 0ustar00philipphilip __init_mapping__ () mapping-1.4.3/inst/PaxHeaders/geo2con.m0000644000000000000000000000006215005124246014720 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/geo2con.m0000644000175000017500000000631715005124246015243 0ustar00philipphilip## Copyright (C) 2022 The Octave Project Developers ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . ## -*- texinfo -*- ## @deftypefn {} {@var{chi} =} geo2con (@var{phi}) ## @deftypefnx {} {@var{chi} =} geo2con (@var{phi}, @var{spheroid}) ## @deftypefnx {} {@var{chi} =} geo2con (@var{phi}, @var{spheroid}, @var{angleUnit}) ## Returns the conformal latitude given geodetic latitude @var{phi} ## ## Input ## @itemize ## @item ## @var{phi}: the geodetic latitude ## @end itemize ## ## @itemize ## @item ## (optional) @var{spheroid}: referenceEllipsoid name, EPSG number, or ## parameter struct: the deualt is wgs84. ## ## @item ## (optional) @var{angleUnit}: string for angular units ('degrees' or 'radians', ## case-insensitive, just the first charachter will do). Default is 'degrees'. ## @end itemize ## ## Output ## @itemize ## @item ## @var{chi}: the conformal latitude ## @end itemize ## ## Example ## @example ## geo2con(45) ## ans = 44.808 ## @end example ## @seealso{geo2auth, geo2iso, geo2rect} ## @end deftypefn function [chi] = geo2con (phi, spheroid ="", angleUnit = "degrees") if (nargin < 1 || nargin > 3) print_usage(); endif if (! isnumeric (phi) || ! isreal (phi)) error ("geo2con: numeric input expected"); endif if (isempty (spheroid)) E = referenceEllipsoid ("wgs84"); else if (isnumeric (spheroid)) spheroid = num2str (spheroid); endif E = sph_chk (spheroid); endif if (! ischar (angleUnit)) error ("geo2con: character value expected for 'angleUnit'"); elseif (strncmpi (angleUnit, "degrees", min (length (angleUnit), 7))) ## Latitude must be within [-90 ... 90] if (any (abs (phi) > 90)) error ("geo2con: azimuth value(s) out of acceptable range [-90, 90]") endif phi = deg2rad (phi); elseif (strncmpi (angleUnit, "radians", min (length (angleUnit), 7))) ## Latitude must be within [-pi/2 ... pi/2] if (any (abs (phi) > pi / 2)) error("geo2con: azimuth value(s) out of acceptable range (-pi/2, pi/2)") endif else error ("geo2con: illegal input for 'angleUnit'"); endif ecc = E.Eccentricity; chi = atan (sinh (asinh (tan (phi)) - ecc .* atanh (ecc .* sin (phi)))); if (strncmpi (angleUnit, "degrees", length (angleUnit))) chi = rad2deg (chi); endif endfunction %!test %! phi = [0:15:90]; %! chi = geo2con (phi); %! Z = degrees2dm(chi - phi); %! check = [0; ... %! -5.755543956550260; ... %! -9.979077451140980; ... %! -11.53895663467140; ... %! -10.00703049899710; ... %! -5.783497189944170; ... %! 0]; %! assert (Z(:,2), check, 1e-6) %!error geo2con ("s") %!error geo2con (5i) mapping-1.4.3/inst/PaxHeaders/axes2ecc.m0000644000000000000000000000006215005124246015061 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/axes2ecc.m0000644000175000017500000000574215005124246015405 0ustar00philipphilip## Copyright (C) 2018-2022 Philip Nienhuis ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or (at ## your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} {@var{ecc} =} axes2ecc (@var{semimajor}, @var{semiminor}) ## @deftypefnx {Function File} {} {@var{ecc} =} axes2ecc (@var{axes}) ## Calculates the eccentricity from semimajor and semiminor axes. ## ## @var{semimajor} and @var{semiminor} are scalars or vectors of ## semimajor and semiminor axes, resp. Alternatively, they can also be ## supplied as coordinate (row) vectors or a N2 matrix with each row ## consisting of a (semimajor, semiminor) pair. ## ## Output arg @var{ecc} is a scalar or column vector of eccentricities. ## ## Examples: ## ## Scalar input: ## @example ## format long ## axes2ecc (6378137, 6356752.314245) ## => 0.0818191908429654 ## @end example ## ## Row vector (semimajor, semiminor): ## @example ## axes2ecc ([6378137, 6356752.314245]) ## => 0.0818191908429654 ## @end example ## ## Multivectors: ## @example ## axes2ecc ([ 71492, 66854; ... ## 6378137, 6356752.314245]) ## ans = ## 0.3543163789650412 ## 0.0818191908429654 ## @end example ## ## @seealso{ecc2flat,flat2ecc} ## @end deftypefn ## Function supplied by anonymous contributor, see: ## https://savannah.gnu.org/patch/index.php?9492 function ecc = axes2ecc (semimajor, semiminor=[]) if (nargin < 1) print_usage (); elseif (ischar (semimajor) || ischar (semiminor)) error ("axes2ecc: input args must be numeric"); elseif (nargin == 1) s = size (semimajor); if (s(2) != 2) error ("axes2ecc: Nx2 matrix expected for arg. #1"); endif ecc = sqrt ((semimajor(:, 1) .^ 2 - semimajor(:, 2) .^ 2) ./ ... (semimajor(:, 1) .^ 2)); else ecc = sqrt ((semimajor .^ 2 - semiminor .^ 2) ./ (semimajor .^ 2)); endif endfunction %!test %! semimajor = 6378137; %! semiminor = 6356752.314245; %! Earth = [ semimajor, semiminor ]; %! Jupiter = [ 71492 , 66854 ]; %! Planets = [ Jupiter ; Earth ]; %! assert (axes2ecc (semimajor, semiminor), 0.0818191908429654, 10e-12); %! assert (axes2ecc (Earth), 0.0818191908429654, 10e-12); %! assert (axes2ecc (Planets), [ 0.354316379; 0.081819190843 ], 10e-10); %! assert (axes2ecc (Planets(:, 1), Planets(:, 2)), [ 0.354316379; 0.081819190843 ], 10e-10); %!error axes2ecc ("a", 1); %!error axes2ecc ([1; 2]); mapping-1.4.3/inst/PaxHeaders/geoshow.m0000644000000000000000000000006215005124246015037 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/geoshow.m0000644000175000017500000000402015005124246015347 0ustar00philipphilip## Copyright (C) 2014-2022 Philip Nienhuis ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} geoshow (@var{shps}) ## @deftypefnx {Function File} geoshow (@var{shps}, @var{clr}) ## Plot a mapstruct created by shaperead. ## ## @var{shps} is the name of a geostruct created by shaperead. ## ## Optional argument @var{clr} can be a predefined color ("k", "c", etc.), an ## RGB triplet, or a 2 X 1 column vector of RGB triplets (each row containing ## a triplet). The uppermost row will be used for points and lines, the ## lowermost row for solid shape features (not yet implemented). ## ## @seealso{mapshow, shapedraw, shapeinfo, shaperead} ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2014-11-17 based on a suggestion by Carnë Draug function geoshow (varargin) if (isshape (varargin{1})) ## Assume a shape struct plotshape (varargin{:}); axis equal; else error ("geoshow: plotting of non-shapes is not yet implemented\n") endif endfunction function retval = isshape (s) retval = false; ## Check if s is a recognized shape file struct; just a brief check if (isstruct (s)) ## Yep. Find out what type fldn = fieldnames (s); if (ismember ("Geometry", fldn) && ismember ("BoundingBox", fldn) && ... ismember ("Lon", fldn)) ## Assume it is a Matlab-style geostruct retval = true; endif endif endfunction mapping-1.4.3/inst/PaxHeaders/rad2km.m0000644000000000000000000000006215005124246014544 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/rad2km.m0000644000175000017500000000427015005124246015063 0ustar00philipphilip## Copyright (C) 2014-2022 Pooja Rao ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{km} =} rad2km (@var{rad}) ## @deftypefnx {Function File} {@var{km} =} rad2km (@var{rad}, @var{radius}) ## @deftypefnx {Function File} {@var{km} =} rad2km (@var{rad}, @var{sphere}) ## Converts angle to distance by multiplying angle with radius. ## ## Calculates the distances @var{km} in a sphere with @var{radius} (also in ## kilometers) for the angles @var{rad}. If unspecified, radius defaults to ## 6371, the mean radius of Earth. ## ## Alternatively, @var{sphere} can be one of "sun", "mercury", "venus", "earth", ## "moon", "mars", "jupiter", "saturn", "uranus", "neptune", or "pluto", in ## which case radius will be set to that object mean radius. ## ## @seealso{deg2km, deg2sm, km2rad, km2deg, ## nm2deg, nm2rad, rad2km, rad2nm, rad2sm, sm2deg, sm2rad} ## @end deftypefn ## Author: Pooja Rao function km = rad2km (rad, radius = "earth") ## This function converts radians (rad) to kilometers (km) ## Check arguments if (nargin < 1 || nargin > 2) print_usage(); elseif (ischar (radius)) ## Get radius of sphere with its default units (km) radius = spheres_radius (radius); ## Check input elseif (! isnumeric (radius) || ! isscalar (radius)) error ("rad2km: RADIUS must be a numeric scalar"); endif km = (rad * radius) ; endfunction %!test %!assert (km2rad (rad2km (10)), 10, 10*eps); %!assert (km2rad (rad2km (10, 80), 80), 10, 10*eps); %!assert (km2rad (rad2km (10, "pluto"), "pluto"), 10, 10*eps); mapping-1.4.3/inst/PaxHeaders/ecef2enu.m0000644000000000000000000000006215005124246015060 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/ecef2enu.m0000644000175000017500000001677115005124246015410 0ustar00philipphilip## Copyright (C) 2014-2022 Michael Hirsch, Ph.D. ## Copyright (C) 2013-2022 Felipe Geremia Nievinski ## Copyright (C) 2020-2022 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{e}, @var{n}, @var{u} =} ecef2enu (@var{x}, @var{y}, @var{z}, @var{lat0}, @var{lon0}, @var{alt0}) ## @deftypefnx {Function File} {@var{e}, @var{n}, @var{u} =} ecef2enu (@var{x}, @var{y}, @var{z}, @var{lat0}, @var{lon0}, @var{alt0}, @var{spheroid}) ## @deftypefnx {Function File} {@var{e}, @var{n}, @var{u} =} ecef2enu (@var{x}, @var{y}, @var{z}, @var{lat0}, @var{lon0}, @var{alt0}, @var{spheroid}, @var{angleUnit}) ## Convert Earth Centered Earth Fixed (ECEF) coordinates to local East, ## North, Up (ENU) coordinates. ## ## Inputs: ## @itemize ## @item ## @var{x}, @var{y}, @var{z}: ## ECEF coordinates of target points (length units equal to length unit of ## used referenceEllipsoid, of which the default is meters). Can be scalars ## but vectors and nD arrays are accepted if they have equal dimensions. ## ## @item ## @var{lat0}, @var{lon0}, @var{alt0}: latitude, longitude and height of local ## observer point(s). Length unit of local height: see above. In case of ## multiple local locations their numbers and dimensions should match those of ## the target points (i.e., one observer location for each target point). ## ## @item ## (Optional) @var{spheroid}: referenceEllipsoid specified as EPSG number, ## ellipsoid name, or parameter struct. An empty string ("") or empty numeric ## array ([]) is also accepted. Default is WGS84. ## ## @item ## (Optional) @var{angleUnit}: string for angular units ('radians' or ## 'degrees'), only the first letter matters. Default is 'd': degrees. ## @end itemize ## ## Outputs: ## @itemize ## @item @var{e}, @var{n}, @var{u}: ## East, North, Up local cartesian coordinates of ## target point(s) (default length unit that of invoked referenceEllipsoid, ## of which the default is meters). ## @end itemize ## ## Example: ## @example ## [e, n, u] = ecef2enu (660930, -4701424, 4246579, 42, -82, 200, ... ## "wgs84", "degrees") ## --> ## e = 186.12 ## n = 286.56 ## u = 939.10 ## @end example ## ## @seealso{enu2ecef, ecef2enuv, ecef2geodetic, ecef2ned, ecef2enu, ## referenceEllipsoid} ## @end deftypefn function [e,n,u] = ecef2enu (varargin) spheroid = ""; angleUnit = "degrees"; if (nargin < 6 || nargin > 8) print_usage(); elseif (nargin == 6) ## Assume lat, lon, alt, lat0, lon0, alt0 given elseif (nargin == 7) if (isnumeric (varargin{7})) ## EPSG spheroid code spheroid = varargin{7}; elseif (ischar (varargin{7})) if (! isempty (varargin{7}) && ismember (varargin{7}(1), {"r", "d"})) angleUnit = varargin{7}; else spheroid = varargin{7}; endif elseif (isstruct (varargin{7})) spheroid = varargin{7}; else error ("ecef2enu: spheroid or angleUnit expected for arg. #7"); endif elseif (nargin == 8) spheroid = varargin{7}; angleUnit = varargin{8}; endif if (isnumeric (spheroid)) spheroid = num2str (spheroid); endif x = varargin{1}; y = varargin{2}; z = varargin{3}; lat0 = varargin{4}; lon0 = varargin{5}; alt0 = varargin{6}; if (! isnumeric (x) || ! isreal (x) || ... ! isnumeric (y) || ! isreal (y) || ... ! isnumeric (z) || ! isreal (z) || ... ! isnumeric (lat0) || ! isreal (lat0) || ... ! isnumeric (lon0) || ! isreal (lon0) || ... ! isnumeric (alt0) || ! isreal (alt0)) error ("ecef2enu : numeric real input expected for first 6 input args."); endif if (! all (size (x) == size (y)) || ! all (size (y) == size (z))) error ("ecef2enu: non-matching dimensions of ECEF inputs."); endif if (! (isscalar (lat0) && isscalar (lon0) && isscalar (alt0))) ## Check if for each test point a matching observer point is given if (! all (size (lat0) == size (x)) || ... ! all (size (lon0) == size (y)) || ... ! all (size (alt0) == size (z))) error (["ecef2enu: non-matching dimensions of observer points and ", ... "target points"]); endif endif E = sph_chk (spheroid); if (! ischar (angleUnit) || ! ismember (lower (angleUnit(1)), {"d", "r"})) error ("ecef2enu: angleUnit should be one of 'degrees' or 'radians'") endif [x0, y0, z0] = geodetic2ecef (E, lat0, lon0, alt0, angleUnit); [e, n, u] = ecef2enuv (x - x0, y - y0, z - z0, lat0, lon0, angleUnit); endfunction %!test %! [e, n, u] = ecef2enu (660930.192761082, -4701424.222957011, 4246579.604632881, 42, -82, 200); %! assert([e, n, u], [186.27752, 286.84222, 939.69262], 10e-6); %!test %! Rad = deg2rad ([42, -82]); %! [e, n, u] = ecef2enu (660930.192761082, -4701424.222957011, 4246579.604632881, Rad(1), Rad(2), 200, "rad"); %! assert ([e, n, u], [186.28, 286.84, 939.69], 10e-3); %!test %! [a, b, c] = ecef2enu (5507528.9, 4556224.1, 6012820.8, 45.9132, 36.7484, 1877753.2); %! assert ([a, b, c], [355601.2616, -923083.1558, 1041016.4238], 1e-4); %!error ecef2enu (45, 45, 100, 50, 50, 200, "", "km") %!error ecef2enu ("A", 45, 100, 50, 50, 200) %!error ecef2enu (45i, 45, 100, 50, 50, 200) %!error ecef2enu (45, "A", 100, 50, 50, 200) %!error ecef2enu (45, 45i, 100, 50, 50, 200) %!error ecef2enu (45, 45, "A", 50, 50, 200) %!error ecef2enu (45, 45, 100i, 50, 50, 200) %!error ecef2enu (45, 45, 100, "A", 50, 200) %!error ecef2enu (45, 45, 100, 50i, 50, 200) %!error ecef2enu (45, 45, 100, 50, "A", 200) %!error ecef2enu (45, 45, 100, 50, 50i, 200) %!error ecef2enu (45, 45, 100, 50, 50, "A") %!error ecef2enu (45, 45, 100, 50, 50, 200i) %!error ecef2enu ([1 1], [2 2]', [3 3], 4, 5, 6) %!error ecef2enu ([1 1], [2 2], [33], 4, 5, 6) %!error ecef2enu ([1 1], [2 2], [3 3], [4 4], 5, 6) %!error ecef2enu ([1 1], [2 2], [3 3], 4, [5 5], 6) %!error ecef2enu ([1 1], [2 2], [3 3], [4; 4], [5; 5], [6; 6]) mapping-1.4.3/inst/PaxHeaders/dxfdraw.m0000644000000000000000000000006215005124246015023 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/dxfdraw.m0000644000175000017500000001265515005124246015350 0ustar00philipphilip## Copyright (C) 2016-2022 Philip Nienhuis ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . ## -*- texinfo -*- ## @deftypefn {} [@var{h}] = dxfdraw (@var{dxf}) ## @deftypefnx {} [@var{h}] = dxfdraw (@var{dxf}, @var{clr}) ## @deftypefnx {} [@var{h}] = dxfdraw (@dots{}, @var{name}, @var{value}, @dots{}) ## Draw a map of a DXF file based on a DXF cell array or DXF drawing struct. ## ## Input argument @var{dxf} is the name of a DXF cell array (see ## dxfread.m), or the name of a DXF file, or a DXF drawing struct made ## by dxfparse. ## ## @var{clr} is the color used to draw the DXF contents. All lines and ## arcs are drawn in the same color; similar for all filled surfaces. ## For points, lines and polylines this can be a 3x1 RGB vector or a color ## code. For polygons it can be a 2x1 vector of color codes or a 2x3 double ## array of RGB entries. The default is [0.7 0.7 0.7; 0.8 0.9 0.99]. ## ## In addition several graphics properties can be specified, e.g., linestyle ## and linewidth. No checks are performed whether these are valid for the ## entities present in the DXF cell array or file. ## ## Currently the following entities are supported: POINT, LINE, POLYLINE, ## LWPOLYLINE, CIRCLE, ARC and 3DFACE. For drawing CIRCLE and ARC entities ## functions from the geometry packge are required. ## ## Optional output argument @var{h} is the graphics handle of the resulting ## map. ## ## @seealso{dxfread, dxfparse} ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2016-01-25 function [h] = dxfdraw (dxf, clr=[0.7 0.7 0.7; 0.8 0.9 0.99], varargin) if (isstruct (dxf)) ## Cursory validation fldnm = fieldnames (dxf); if (! all (ismember({"i3d", "ic", "ia", "j3", "jr", "il", "ip"}, fldnm))) error ("dxfdraw: invalid struct input for arg #1"); endif else if (isempty (dxf)) return elseif (iscell (dxf)) ## Cursory Q-checks: minumum 3 columns, col 1 & 3 numeric, col #2 character if (size (dxf, 2) < 3 || ! all (all (cellfun (@isnumeric, dxf(:, [1, 3])))) ... || ! all (cellfun (@ischar, dxf(:, 2)))) error ("dxfdraw: input arg #1 does not look like a valid dxf cell array"); endif elseif (ischar (dxf)) ## Maybe a DXF file? [~, ~, ext] = fileparts (dxf); if (isempty (ext) || ! strcmpi (ext, ".dxf")) ## Just add a .dxf suffix dxf = [dxf ".dxf"]; endif fid = fopen (dxf); if (fid < 0) error ("File '%s' not found", dxf); else fclose (fid); endif ## Read DXF file into DXF cell array dxf = dxfread (dxf); else error (["dxfdraw: DXF cell array, DXF file name, or DXF drawing ", ... "struct expected for arg #1 "]); endif ## parse DXF cell array into a DXF drawing struct dxf = dxfparse (dxf, 0); endif ## We should have a valid struct now. Extract data i3d = dxf.i3d; is = dxf.is; ir = dxf.ir; ic = dxf.ic; ia = dxf.ia; j3 = dxf.j3; jr = dxf.jr; il = dxf.il; ip = dxf.ip; jf = dxf.jf; jw = dxf.jw; jl = dxf.jl; XYZ = dxf.XYZ; XYZp = dxf.XYZp; XY = dxf.XY; CIRCLES = dxf.CIRCLES; ARCS = dxf.ARCS; VRT3 = dxf.VRT3; FAC3 = dxf.FAC3; LWP = dxf.LWP; LWV = dxf.LWV; VRTS = dxf.VRTS; FACP = dxf.FACP; ## dxf not needed from here, clear it as it may hold lots of RAM needed for plot clear dxf; h = figure (); hold on; axis equal; if (i3d) if (is > 0) plot3 (XYZp(:, 1), XYZp(:, 2), XYZp(:, 3), "color", clr(1, :), varargin{:}); endif if (ir > 0) plot3 (XYZ(:, 1), XYZ(:, 2), XYZ(:, 3), "color", clr(1, :), varargin{:}); endif if (ic > 0) drawCircle3d (CIRCLES, "color", clr(1, :), varargin{:}); endif if (ia > 0) drawCircleArc3d (ARCS, "color", clr(1, :), varargin{:}); endif if (j3 > 0) patch ("vertices", VRT3, "faces", FAC3, "edgecolor", clr(1, :), ... "facecolor", clr(2, :), varargin{:}); endif else if (is > 0) plot (XYZp(:, 1), XYZp(:, 2), "color", clr(1, :), varargin{:}); endif if (ir > 0) plot (XYZ(:, 1), XYZ(:, 2), "color", clr(1, :), varargin{:}); endif if (ic > 0) drawCircle (CIRCLES, "color", clr(1, :), varargin{:}); endif if (ia > 0) drawCircleArc (ARCS, "color", clr(1, :), varargin{:}); endif if (jr > 0) plot (XY(:, 1), XY(:, 2), "color", clr(1, :), varargin{:}); endif if (il > 0) LWV(jw+1:end, :) = []; LWV(LWV == 0) = NaN; patch ("vertices", LWP, "faces", LWV, "edgecolor", clr(1, :), ... "facecolor", clr(2, :), varargin{:}); endif endif if (ip > 0) FACP(jf+1:end, :) = []; FACP(FACP == 0) = NaN; if (! i3d) VRTS(:, 3) = []; endif patch ("vertices", VRTS, "faces", FACP, "edgecolor", clr(1, :), ... "facecolor", clr(2, :), varargin{:}); endif endfunction mapping-1.4.3/inst/PaxHeaders/geodeticLatitudeFromGeocentric.m0000644000000000000000000000006215005124246021472 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/geodeticLatitudeFromGeocentric.m0000644000175000017500000000711515005124246022012 0ustar00philipphilip## Copyright (C) 2018-2022 Philip Nienhuis ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{phi} =} geodeticLatitudeFromGeocentric (@var{psi}, @var{flattening}) ## @deftypefnx {Function File} {@var{phi} =} geodeticLatitudeFromGeocentric (@var{psi}, @var{flattening}, @var{angleUnit}) ## Return geodetic latitude (phi) given geocentric latitude (psi) and flattening. ## ## The default input and output is in degrees; use optional third parameter ## @var{angleUnit} for radians. @var{psi} can be a scalar, vector, matrix or ## any ND array. @var{flattening} must be a scalar value in the interval ## [0..1). ## ## Examples ## Scalar input: ## @example ## phi = geodeticLatitudeFromGeocentric (45, 0.0033528) ## => phi = ## 45.192 ## @end example ## ## Also can use radians: ## @example ## phi = geodeticLatitudeFromGeocentric (pi/4, 0.0033528, "radians") ## => phi = ## 0.78876 ## @end example ## ## Vector Input: ## @example ## psi = 35:5:45; ## phi = geodeticLatitudeFromGeocentric (psi, 0.0033528) ## => phi = ## 35.181 40.19 45.192 ## @end example ## ## @seealso{geocentricLatitude, geodeticLatitudeFromGeocentric, parametricLatitude} ## @end deftypefn ## Function supplied by anonymous contributor, see: ## https://savannah.gnu.org/patch/index.php?9640 function phi = geodeticLatitudeFromGeocentric (psi, flattening, angleUnit="degrees") if (nargin < 2 || isempty (angleUnit)) print_usage (); endif if (! isnumeric (psi) || ! isreal (psi) || ... ! isnumeric (flattening) || ! isreal (flattening)) error ("geodeticLatitudeFromGeocentric: numeric input expected"); elseif (! isscalar (flattening)) error ("geodeticLatitudeFromGeocentric: scalar value expected for flattening"); elseif (flattening < 0 || flattening >= 1) error ( "geodeticLatitudeFromGeocentric: flattening must lie in the real interval [0..1)" ) elseif (! ischar (angleUnit) ||! ismember (lower (angleUnit(1)), {"d", "r"})) error ("geodeticLatitudeFromGeocentric: angleUnit should be one of 'degrees' or 'radians'"); endif if (strncmpi (angleUnit, "r", 1) == 1) phi = atan2 (tan (psi), (1 - flattening) ^ 2); else phi = atan2d (tand (psi), (1 - flattening) ^ 2); endif endfunction %!test %! earth_flattening = 0.0033528; %! assert (geodeticLatitudeFromGeocentric (45, earth_flattening), 45.1924226, 10e-6); %! assert (geodeticLatitudeFromGeocentric (pi/4, earth_flattening, 'radians'), 0.78876, 10e-6); %!error geodeticLatitudeFromGeocentric (0.5, "flat") %!error geodeticLatitudeFromGeocentric (0.5, 5i ) %!error geodeticLatitudeFromGeocentric ("psi", 0.0033528) %!error geodeticLatitudeFromGeocentric (5i, 0.0033528 ) %!error geodeticLatitudeFromGeocentric ([45 50], [0.7 0.8]) %!error geodeticLatitudeFromGeocentric (45, 1) %!error geodeticLatitudeFromGeocentric (45, 0.0033528 ,"km") mapping-1.4.3/inst/PaxHeaders/wrapTo2Pi.m0000644000000000000000000000006215005124246015213 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/wrapTo2Pi.m0000644000175000017500000000366415005124246015540 0ustar00philipphilip## Copyright (C) 2015-2022 Oscar Monerris Belda ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{xwrap} =} wrapTo2Pi (@var{x}) ## ## Wraps x into the [0 to 2pi] interval ## ## @var{x}: angle in radians (single value, vector or ND matrix). ## ## @var{xwrap}: output value(s) in the range [0 .. 2*pi] radians. ## The interval [0 .. 2*pi] is a closed interval: values equal to ## zero or negative even multiples of pi are mapped to 0, values ## equal to an even multiple of pi are mapped to 2*pi. ## ## Example: ## @example ## wrapTo2Pi ([-2*pi, -pi, 0, pi; 0.1, pi, 4*pi, 5*pi]) ## ans = ## 0.00000 3.14159 0.00000 3.14159 ## 0.10000 3.14159 6.28319 3.14159 ## @end example ## ## @seealso{wrapTo180, wrapTo360, wraptoPi} ## @end deftypefn function xwrap = wrapTo2Pi(x) xwrap = rem (x-pi, 2*pi); idx = find (abs (xwrap) > pi); xwrap(idx) -= 2*pi * sign (xwrap(idx)); xwrap += pi; endfunction %!test %! x = -9:0.1:9; %! xw = wrapTo2Pi (x); %! assert (sin (x), sin (xw), 8 * eps) %! assert (cos (x), cos (xw), 8 * eps) %! assert (! any (xw < 0)) %! assert (! any (xw > 2 * pi)) %% Test Matlab compatibility as regards closed interval (esp. left) %!test %! assert (wrapTo2Pi ([-2*pi, -pi, 0, pi; 0.1, pi, 4*pi, 5*pi]), ... %! [0, pi, 0, pi; 0.1, pi, 2*pi, pi], 1e-13); mapping-1.4.3/inst/PaxHeaders/gmlread.m0000644000000000000000000000006215005124246014777 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/gmlread.m0000644000175000017500000002042215005124246015313 0ustar00philipphilip## Copyright (C) 2017-2022 Philip Nienhuis ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . ## -*- texinfo -*- ## @deftypefn {} {@var{gml} =} gmlread (@var{fname}, @var{dots}) ## Read a .gml (Geographic Markup Language) file. ## ## gmlread only reads coordinates, no attributes. ## ## Required input argument @var{fname} is the name of a .gml file. If ## no other arguments are specified all features in the entire .gml file ## will be read. ## ## The following optional property/value pairs (all case-insensitive) ## can be specified to select only some feature types and/or features ## limited to a certain area: ## ## @itemize ## @item "FeatureType" ## (Just one "f" will do) Only read a certain feature type; the value ## can be one of "Points", "LineStrings" or "Polygons" (only the first ## three characters matter). Multiple feature types can be selected by ## specifying multiple FeatureType property/value pairs. ## ## @item BoundingBox ## (just one "b" suffices) Only read features that lie entirely within ## a coordinate rectangle specified as a 2x2 matrix containing [minX minY; ## maxX maxY]. ## @end itemize ## ## In addition verbose output can be obtained by specifying the following ## property/value pair: ## ## @itemize ## @item Debug ## (a "d" will do) followed by a numeric value of 1 (or true) specifies ## verbose output; a numeric value of 0 (or false) suppresses verbose output. ## @end itemize ## ## The output of gmlread comprises a struct containing up to three ## mapstructs (MultiPoint and/or Polyline and/or Polygon mapstructs), ## depending on optional featuretype selection. ## ## @seealso{shaperead} ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2017-03-06 function [gml] = gmlread (fname, varargin) ## FIXME Input validation fid = fopen (fname, "r"); if (fid < 0) error ("gmlread: file %s not found.\n", fname); endif ## Process [property, value] options idx = pol = []; dbug = feat = ipt = iln = ipg = 0; for ii=1:2:numel (varargin) if (ischar (varargin{ii}) && numel (varargin{ii}) > 0 && mod (numel (varargin), 2) == 0) switch lower (varargin{ii})(1) case "f" ## Feature type. Keep track of whether this option was entered feat = 1; if (ischar (varargin{ii+1})) switch lower (varargin{ii+1})(1:3) case "poi" ipt = 1; case "lin" iln = 1; case "pol" ipg = 1; otherwise error ("gmlread: unknown FeatureType '%s'", varargin{ii+1}); endswitch else error ("gmlread: illegal value for argument %d\n", ii+1); endif case "b" ## Bounding box bbox = varargin{ii+1}; if (! isnumeric (idx) && size (bbox, 1) != 2 && size (bbox, 2) != 2) error ("gmlread: numeric 2x2 matrix expected for arg.# %d\n", ii+1); else pol = [bbox(1, 1), bbox(2, 1), bbox(2, 1), bbox(1, 1), bbox(1, 1); ... bbox(1, 2), bbox(1, 2), bbox(2, 2), bbox(2, 2), bbox(1, 2)]; endif case ("d") ## Debug dbug = varargin{ii+1} == 1; otherwise warning ("gmlread: unknown option '%s' - ignored\n", varargin{ii}); endswitch else error ("gmlread: wrong [property, value] options list"); endif endfor if (! feat) ipt = iln = ipg = 1; endif if (dbug) printf ("Reading %s ... ", fname); endif xml = fread (fid, 1000, "char=>char")'; ## Skip header lines/-nodes hdls = cell2mat (regexp (xml, '(<\?.*?\?>)|()', "tokenExtents")); spos = hdls(end); ## Start with outer content node fseek (fid, spos+1, "bof"); xml = fread (fid, Inf, "char=>char")'; fclose (fid); ## Parse xml int 5xN cell array ptrn = '([\d\. ]*?)'; feats = reshape (cell2mat (regexp (xml, ptrn, "tokens")), 5, []); if (ipt) if (dbug) printf ("\nSearching Points ... "); endif ipt = find (strcmp (feats(1, :), "Point")); if (dbug) printf ("%d found.\n", numel (ipt)); endif else ipt = []; endif if (iln) if (dbug) printf ("Searching LineStrings ... "); endif iln = find (strcmp (feats(1, :), "LineString")); if (dbug) printf ("%d found.\n", numel (iln)); endif else iln = []; endif if (ipg) if (dbug) printf ("Searching Polygons ... "); endif ipg = find (strcmp (feats(1, :), "Polygon")); if (dbug) printf ("%d found.\n", numel (ipg)); endif else ipg = []; endif if (dbug) printf ("Converting ....\n", numel (ipg)); endif ## Points if (! isempty (ipt)) gmlpt = repmat (struct ("Geometry", "Multipoint", "X", NaN (1, 10), "Y", NaN (1, 10), "BoundingBox", NaN (2, 2)), numel (ipt), 1); jpt = 0; for ii=1:numel (ipt) if (dbug) printf ("%d of %d Points ....\r", ii, numel (ipt)); endif [xy, cnt] = sscanf (feats{4, ipt(ii)}, "%f"); dimsn = str2double (feats{3, ipt(ii)}); xy = reshape (xy, dimsn, []); if (isempty (pol) || bbox <= 0 || all (inpolygon (xy(1, :), xy(2, :), pol(1, :), pol(2, :)))) ++jpt; gmlpt(jpt).X = xy(1, :); gmlpt(jpt).Y = xy(2, :); gmlpt(jpt).BoundingBox = [min(xy(1, :)), min(xy(2, :)); max(xy(1, :)), max(xy(2, :))]; if (dimsn >= 3) gmlpt(jpt).Z = xy(3, :); gmlpt(jpt).BoundingBox = [gmlpt(jpt).BoundingBox, [min(xy(3, :)); max(xy(3, :))]]; endif endif endfor if (dbug) printf ("\n"); endif gml.Points = gmlpt(1:jpt); endif ## LineStrings if (! isempty (iln)) jpt = 0; gmlpl = repmat (struct ("Geometry", "Polyline", "X", NaN (1, 15), "Y", NaN (1, 15), "BoundingBox", NaN (2, 2)), numel (iln), 1); for ii=1:numel (iln) if (dbug) printf ("%d of %d LineStrings ....\r", ii, numel (iln)); endif [xy, cnt] = sscanf (feats{4, iln(ii)}, "%f"); dimsn = str2double (feats{3, iln(ii)}); xy = reshape (xy, dimsn, []); if (isempty (pol) || all (inpolygon (xy(1, :), xy(2, :), pol(1, :), pol(2, :)))) ++jpt; gmlpl(jpt).X = xy(1, :); gmlpl(jpt).Y = xy(2, :); gmlpl(jpt).BoundingBox = [min(xy(1, :)), min(xy(2, :)); max(xy(1, :)), max(xy(2, :))]; if (dimsn >= 3) gmlpl(jpt).Z = xy(3, :); gmlpl(jpt).BoundingBox = [gmlpl(jpt).BoundingBox, [min(xy(3, :)); max(xy(3, :))]]; endif endif endfor if (dbug) printf ("\n"); endif gml.Polylines = gmlpl(1:jpt); endif ## Polygons if (! isempty (ipg)) jpt = 0; gmlpg = repmat (struct ("Geometry", "Polygon", "X", NaN (1, 20), "Y", NaN (1, 20), "BoundingBox", NaN (2, 2)), numel (ipg), 1); for ii=1:numel (ipg) if (dbug) printf ("%d of %d Polygons ....\r", ii, numel (ipg)); endif [xy, cnt] = sscanf (feats{4, ipg(ii)}, "%f"); dimsn = str2double (feats{3, ipg(ii)}); xy = reshape (xy, dimsn, []); if (isempty (pol) || all (inpolygon (xy(1, :), xy(2, :), pol(1, :), pol(2, :)))) ++jpt; gmlpg(jpt).X = xy(1, :); gmlpg(jpt).Y = xy(2, :); gmlpg(jpt).BoundingBox = [min(xy(1, :)), min(xy(2, :)); max(xy(1, :)), max(xy(2, :))]; if (dimsn >= 3) gmlpg(jpt).Z = xy(3, :); gmlpg(jpt).BoundingBox = [gmlpg(jpt).BoundingBox, [min(xy(3, :)); max(xy(3, :))]]; endif endif endfor if (dbug) printf ("\n"); endif gml.Polygons = gmlpg(1:jpt); endif endfunction mapping-1.4.3/inst/PaxHeaders/removeExtraNanSeparators.m0000644000000000000000000000006215005124246020366 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/removeExtraNanSeparators.m0000644000175000017500000001176015005124246020707 0ustar00philipphilip## Copyright (C) 2014-2022 Carnë Draug ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or (at ## your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{x}, @var{y}, @dots{}] =} removeExtraNanSeparators (@var{x}, @var{y}, @dots{}) ## Remove groups of NaN and leave a single separator. ## ## For any number of vectors, @var{x}, @var{y}, @var{z}, @dots{}, reduce ## groups of contiguous NaNs into a single NaN separator. The vectors must ## all have the same dimensions and the NaNs must be locations. Leading NaNs ## are removed, and trailing NaNs are reduced to one. ## ## @example ## @group ## removeExtraNanSeparators ([NaN NaN 3 4 5 NaN NaN 8 NaN], [NaN NaN 7 6 5 NaN NaN 2 NaN]) ## @result{} ## [3 4 5 NaN 8 NaN] ## @result{} ## [7 6 5 NaN 2 NaN] ## @end group ## @end example ## ## @seealso{diff, isnan, isna} ## @end deftypefn ## Author: Carnë Draug function [varargout] = removeExtraNanSeparators (varargin) if (nargin < 1) print_usage (); elseif (! isvector (varargin{1}) || ! size_equal (varargin{:})) error ("removeExtraNanSeparators: X, Y, Z, ... must be vectors with equal sizes"); endif ## one row per input argument if (iscolumn (varargin{1})) ins = cell2mat (varargin)'; else ins = cell2mat (varargin'); endif nans = isnan (ins); if (any (nans(:))) if (any (any (nans) != all (nans))) error ("removeExtraNanSeparators: NaN and NA positions must be equal on X, Y, Z, ..."); endif ## This will create a mask that selects the first change from a non-NaN ## into a NaN. If there are leaading NaN it will not identify them but ## it will identify the first of trailing NaNs. nan_sep = diff ([true nans(1,:)]) == 1; line_mask = ! nans(1,:) | nan_sep; full_mask = repmat (line_mask, [nargin 1]); elems = nnz (line_mask); outs = reshape (ins(full_mask), [nargin elems]); if (iscolumn (varargin{1})) varargout = mat2cell (outs', elems, ones (nargin, 1)); else varargout = mat2cell (outs, ones (nargin, 1), elems); endif else ## there are no NaNs, so give the input back varargout = varargin; endif endfunction ## We remove trailing NaN and leave only one at the end %!assert (nthargout (1:2, @removeExtraNanSeparators, %! [NaN NaN 3 4 5 6 NaN NaN], [NaN NaN 4 5 5 7 NaN NaN]), %! {[ 3 4 5 6 NaN ], [ 4 5 5 7 NaN ]}); ## We leave individual NaN in the middle intact %!assert (nthargout (1:2, @removeExtraNanSeparators, %! [NaN NaN 3 4 NaN 6 NaN], [NaN NaN 2 4 NaN 3 NaN]), %! {[ 3 4 NaN 6 NaN], [ 2 4 NaN 3 NaN]}); ## We turn a group of NaN into a single separator %!assert (nthargout (1:2, @removeExtraNanSeparators, %! [NaN 2 NaN NaN 6 NaN], [NaN 1 NaN NaN 8 NaN]), %! {[ 2 NaN 6 NaN], [ 1 NaN 8 NaN]}); %!assert (nthargout (1:2, @removeExtraNanSeparators, %! [1 2 NaN NaN 6 NaN], [8 1 NaN NaN 8 NaN]), %! {[1 2 NaN 6 NaN], [8 1 NaN 8 NaN]}); ## We don't mess up when there's no trailing(s) NaN %!assert (nthargout (1:2, @removeExtraNanSeparators, %! [1 2 NaN NaN 6], [8 1 NaN NaN 8]), %! {[1 2 NaN 6], [8 1 NaN 8]}); ## We don't mess up when there's no NaN's at all %!assert (nthargout (1:2, @removeExtraNanSeparators, 1:9, 1:9), {1:9 1:9}) %!assert (nthargout (1:2, @removeExtraNanSeparators, 9:-1:-9, 9:-1:-9), {9:-1:-9 9:-1:-9}) ## We don't mess up for x, y, z, etc %!assert (nthargout (1:3, @removeExtraNanSeparators, %! [1 2 NaN NaN 6], [8 1 NaN NaN 8], [5 6 NaN NaN 7]), %! {[1 2 NaN 6], [8 1 NaN 8], [5 6 NaN 7]}); ## We don't mess up when we get column vector instead of row vectors %!assert (nthargout (1:3, @removeExtraNanSeparators, %! [1 2 NaN NaN 6]', [8 1 NaN NaN 8]', [5 6 NaN NaN 7]'), %! {[1 2 NaN 6]', [8 1 NaN 8]', [5 6 NaN 7]'}); %!error removeExtraNanSeparators (rand (5), rand (5)) %!error removeExtraNanSeparators (rand (5, 1), rand (6, 1)) %!error removeExtraNanSeparators (rand (5, 1), rand (5, 1), rand (5)) %!error removeExtraNanSeparators (rand (5, 1), rand (5, 1), rand (6, 1)) %!error removeExtraNanSeparators ([NaN NaN 3 4 5 6 NaN], [NaN 2 3 4 5 6 NaN]) %!error removeExtraNanSeparators ([NaN NaN 3 4 5 6 NaN], [NaN NaN 3 4 5 6 NaN], [NaN 2 3 4 5 6 NaN]) mapping-1.4.3/inst/PaxHeaders/rad2sm.m0000644000000000000000000000006215005124246014554 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/rad2sm.m0000644000175000017500000000447215005124246015077 0ustar00philipphilip## Copyright (C) 2014-2022 Pooja Rao ## Copyright (C) 2018-2022 Philip Nienhuis ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{sm} =} rad2sm (@var{rad}) ## @deftypefnx {Function File} {@var{sm} =} rad2sm (@var{rad}, @var{radius}) ## @deftypefnx {Function File} {@var{sm} =} rad2sm (@var{rad}, @var{sphere}) ## Converts angle in radians to distance in statute miles by multiplying angle ## with radius. ## ## Calculates the distances @var{sm} in a sphere with @var{radius} (also in ## statute miles) for the angles @var{rad}. If unspecified, radius defaults to ## 3958 sm, the mean radius of Earth. ## ## Alternatively, @var{sphere} can be one of "sun", "mercury", "venus", "earth", ## "moon", "mars", "jupiter", "saturn", "uranus", "neptune", or "pluto", in ## which case radius will be set to that object's mean radius. ## ## @seealso{deg2km, deg2nm, deg2sm, km2rad, km2deg, ## nm2deg, nm2rad, rad2km, rad2nm, sm2deg, sm2rad} ## @end deftypefn ## Built with insight from ## Author: Pooja Rao ## Adapted from deg2km.m by Anonymous contributor, see patch #9709 function sm = rad2sm (rad, radius = "earth") ## Check arguments if (nargin < 1 || nargin > 2) print_usage(); elseif (ischar (radius)) ## Get radius of sphere with its default units (km) radius = km2sm (spheres_radius (radius)); ## Check input elseif (! isnumeric (radius) || ! isreal (radius)) error ("rad2sm: RADIUS must be a numeric scalar"); endif sm = (rad * radius); endfunction %!test %!assert (sm2rad (rad2sm (10)), 10, 10*eps); %!assert (sm2rad (rad2sm (10, 80), 80), 10, 10*eps); %!assert (sm2rad (rad2sm (10, "pluto"), "pluto"), 10, 10*eps); %!error rad2sm (5, 5i) mapping-1.4.3/inst/PaxHeaders/mapshow.m0000644000000000000000000000006215005124246015042 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/mapshow.m0000644000175000017500000003721315005124246015364 0ustar00philipphilip## Copyright (C) 2014-2022 Philip Nienhuis ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} @var{H} = mapshow (@var{data}) ## @deftypefnx {Function File} @var{H} = mapshow (@var{data}, @var{clr}) ## @deftypefnx {Function File} @var{H} = mapshow (@var{data}, @var{clr}, ...) ## @deftypefnx {Function File} @var{H} = mapshow (@var{data}, ...) ## @deftypefnx {Function File} @var{H} = mapshow (@var{X}, @var{Y}) ## @deftypefnx {Function File} @var{H} = mapshow (@var{X}, @var{Y}, @var{clr}) ## Draw a map based on raster or shapefile data. ## ## @var{data} can be: ## ## @itemize ## @item The filename of a GIS raster file (any file supported by the GDAL ## library) or of an ArcGIS shapefile. mapshow will invoke rasterread.m ## and rasterdraw.m. If no file extension is specified (just base name) ## mapshow assumes it is a shapefile. ## ## @item A raster band struct created by rasterread.m; in that case the ## corresponding raster info struct (also made by rasterread.m) is required ## as second input argument. ## ## @item A struct created by shaperead.m. @var{data} can be a mapstruct or ## an Octave-style shape struct. ## ## @item The base name or full file name of an ArcGis shape file. mapshow ## will invoke shaperead.m and shapedraw.m ## @end itemize ## ## If the first two arguments to mapshow.m contain numeric vectors, mapshow ## will simply draw the vectors as XY lines. The vectors can contain NaNs (in ## identical positions) to separate parts. ## ## For raster maps currently no further input arguments are recognized. ## For shapefile data, optional argument @var{clr} can be a predefined color ## ("k", "c", etc.), and RGB triplet, or a 2 X 1 column vector of predefined ## colors or RGB triplets (each row containing a predefined color or triplet). ## The upper row will be used for points and lines, the lower row for solid ## shape features. For XY data, only the first row is used. One-character ## color codes can be preceded by one-character linestyle indicators ## (":", "-", "--", "-.") to modify the linestyle for polylines, or marker ## styles ("o", "*", ".", "+", "@", ">", "<", "s", "d", "h", "v", "^") for ## points. ## ## Any other arguments are considered graphics properties for (multi-)points, ## polylines and polygons and will be conveyed as-is to the actual plotting ## routines. ## ## Additionally, if the first argument is a shape struct, mapshow accepts a ## property-value pair "symbolspec" (minimum abbreviation "symb") with a value ## comprising a cell array containing instructions on how to display the ## shape contents. Multiple sympolspec property/value pairs can be specified. ## ## Return argument @var{h} is a handle to the plot figure. ## ## ## Examples: ## ## @example ## H = mapshow ("/full/path/to/map") ## (draws a raster map and returns the figure handle in H) ## @end example ## ## @example ## H = mapshow ("shape.shp", ":g") ## H = mapshow ("shape.shp", "color", "g", "linestyle", ":") ## (draws a polygon shapefile "shape.shp" with green ## dotted lines and return figure handle in H) ## @end example ## ## @example ## mapshow (X, Y, "k") ## (plot vectors X and Y in black color) ## @end example ## ## @example ## mapshow (X, Y, "-.r", "linewidth", 5) ## (plot vectors X and Y as a dashdotted thick red line) ## @end example ## ## @example ## mapshow (data, "symbolspec", symsp1, "symb", symsp2) ## (draw contents of shapestruct (or mapstruct) data ## according to the symbolspecs symsp1 and symsp2) ## @end example ## ## @seealso{geoshow, shapedraw, shapeinfo, shaperead, shapewrite, makesymbolspec, rasterread, rasterdraw, rasterinfo} ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2014-11-17 after a suggestion by Carnë Draug ## Updates: ## 2014-2015 many many fixes ## 2015-02-04 Relax check for mapstructs; don't test BoundingBox (Point shapes) ## 2015-02-11 Fix minor syntax error in do_symspecs rule check function h = mapshow (varargin) ## Check "hold" state; creates a new figure if none was present if (ishold()) old_holdstate = "on"; else old_holdstate = "off"; endif hold on; if ischar (varargin{1}) [fp, fn, ext] = fileparts (varargin{1}); if (isempty (ext)) ## Find out what type of file fl = dir ([fp filesep fn ".*"]); if (isempty (fl)) error ("mapshow: file '%s.*' not found", varargin{1}); endif id = find (! cellfun ("isempty", strfind (lower ({fl.name}), ".shp"))); varargin{1} = [fp filesep fl(id).name]; ## Directly plot shapefile. Strip away symbolspecs isym = find (strncmpi ("symbolspec", varargin(2:end), 4)); if (! isempty (isym)) warning ("mapshow: ignoring symbolspecs when drawing .shp directly"); endif varargin(isym:isym+1) = []; h = shapedraw (varargin{:}); elseif (strncmpi (lower (ext), ".shp", 4)) ## Directly plot shapefile. Strip away symbolspecs isym = find (strncmpi ("symbolspec", varargin(2:end), 4)); if (! isempty (isym)) warning ("mapshow: ignoring symbolspecs when drawing .shp directly"); endif varargin(isym:isym+1) = []; h = shapedraw (varargin{:}); else ## Assume any raster file h = rasterdraw (varargin{1}); endif elseif (nargin > 1 && israster (varargin{1}) && isstruct (varargin{2})) ## Assume raster structs h = rasterdraw (varargin{:}); elseif (isshape (varargin{1})) ## Assume a shape struct or a shape file name. Get optional symbolspec isym = find (strncmpi("symbolspec", varargin(2:end), 4)); if (! isempty (isym)) ## FIXME move this stanze into a separate subfunction ## Found symbolspec. Check if it can be invoked if (ischar (varargin{1})) ## Symbolspec not applicable to shape file argument error ("mapshow: symbolspec not supported when plotting shape files directly\n"); endif ## First get & check geometry symspecs = {varargin{isym+2}}; h = do_symspecs (varargin{1}, symspecs); else ## No symbolspec to process; plot shape(file) directly endif elseif (nargin >= 2 && isvector (varargin{1}) && isvector (varargin{2})) ## Assume args #1 & #2 are lines. Find optional color argument. if (nargin >= 3) if (ischar (varargin{3})) ## Assume arg #3 is a valid color name or character like 'b' h = plot (varargin{1}, varargin{2}, varargin{3}); elseif (isnumeric (varargin{3} && size (varargin{3}, 2) == 3)) ## Assume arg#3 is a valid color triplet h = plot (varargin{1}, varargin{2}, "color", varargin{3}); else error ("mapshow: color argment expected for arg. #3\n"); endif axis equal; else ## Plot args #1 & #2 without further ado h = plot (varargin{1}, varargin{2}, "color", [0.6 0.6 0.6]); endif else error ("mapshow: only plotting of shapes or vector data is implemented\n"); endif ## Reset hold state hold (old_holdstate); axis equal; if (! nargout) h = 0; endif endfunction ##-------------------------------------------------------------------------- ## Copyright (C) 2014,2015 Philip Nienhuis function retval = isshape (s) retval = false; ## Check if s is a recognized shape file struct; just a brief check if (isstruct (s)) ## Yep. Find out what type fldn = fieldnames (s); if (all (ismember ({"vals", "shpbox"}, fldn))) ## Assume it is an Octave-style struct read by shaperead retval = 2; elseif (all (ismember ({"Geometry", "X"}, fldn))) ## Assume it is a Matlab-style mapstruct retval = 1; endif endif endfunction ##-------------------------------------------------------------------------- ## Copyright (C) 2015 Philip Nienhuis function retval = israster (s) retval = 0; ## Check if s is a recognized raster struct; just a brief check if (isstruct (s)) ## Yep. Find out what type fldn = fieldnames (s); if (ismember ("data", fldn) && ismatrix (s.data)) ## Assume it is an Octave-style struct read by shaperead retval = 1; endif endif endfunction ##-------------------------------------------------------------------------- ## Copyright (C) 2015 Philip Nienhuis ## ## Process symbolspecs one by one function h = do_symspecs (shp, symspecs) for jj=1:numel (symspecs); symspec = symspecs{jj}; geom = lower (symspec {1}); if (! ischar (geom)) error ("mapshow: char argument expected for Geometry field in symbolspec\n"); elseif (! ismember (lower (geom), {"point", "multipoint", "line", ... "polyline", "polygon", "patch"})) error ("mapshow: unknown Geometry: %s in symbolspec\n", geom); endif for ii=2:numel (symspec) rule = symspec{ii}; if (! ischar (rule{1})) warning ("mapshow: char string expected for attribute of rule %d in symbolspec\n", ii-1); endif ## Get property or attribute if (strcmpi (rule{1}, "default")) ## Rule applies to all shape features with geom. Plot shape features if (isshape (shp) == 1) ## mapstruct shapes are allowed to be heterogeneous gdx = find (strcmpi (geom, {shp.Geometry})); h = shapedraw (shp(gdx), rule(3:end){:}); elseif (isshape (shp) == 2) h = shapedraw (shp, rule(3:end){:}); else error ("mapshow: improper shape struct type\n"); end elseif (isshape (shp) == 1) ## ML mapstruct type shape struct. Apply to proper geometry features gdx = find (strcmpi (geom, {shp.Geometry})); ## Rule applies to one specific attribute. Check if it exists if (ismember (rule{1}, fieldnames (shp))) ## Try to apply rule. We need try-catch to catch non-matching classes if (islogical (rule{2})) ## Find attributes that are true. FIXME catches zero attributes too try idx = find ([shp(gdx).(rule{1})]); catch warning ("mapshow: rule %d not applicable to atribute %s\n", ... ii-1, rule{1}); end_try_catch elseif (isnumeric (rule{2})) ## Check which shape features have attribute values in the range minr = min (rule{2}); maxr = max (rule{2}); try idx = find ([shp(gdx).(rule{1})] >= minr & ... [shp(gdx).(rule{1})] <= maxr); catch warning ("mapshow: rule %d not applicable to atribute %s\n", ... ii-1, rule{1}); end_try_catch elseif (ischar (rule{2})) ## Match strings try idx = find (strcmp (rule{2}, {shp(gdx).(rule{1})})); catch warning ("mapshow: rule %d not applicable to atribute %s\n", ... ii-1, rule{1}); end_try_catch endif ## Plot shape features h = shapedraw (shp(gdx(idx)), rule(3:end){:}); else ## Attribute not found warning ("mapshow: attribute '%s' in rule #%d not found\n", rule(ii){1}); endif elseif (isshape (shp) == 2) ## Oct-style shp struct. Prepare indexing into coords shp.idx = [ shp.idx; (size(shp.vals, 1) + 2) ]; ## Some fields are not explicitly in the shape switch rule{1} ## Coordinates case "X" shp_field = shp.vals(:, 1); case "Y" shp_field = shp.vals(:, 2); case "Z" shp_field = shp.vals(:, 3); case "M" ## Measure shp_field = shp.vals(:, 4); case "npt" ## Nr. or points/vertices shp_field = shp.npt; case "npr" ## Nr. of parts try shp_field = cellfun (@numel, shp.npr); catch warning ("mapshow: rule %d attribute 'npr' not found\n", ii-1); shp_field = NaN; end_try_catch #case "bbox" # shp_field = shp.bbox; otherwise ## "Regular" attributes if (ismember (rule{1}, fieldnames(shp))) shp_field = shp.(rule{1}); else warning ("mapshow: rule %d attribute '%s' not found\n", ... ii-1, rule{1}); endif endswitch ## Try to apply rule. We need try-catch to catch non-matching classes if (islogical (rule{2})) ## Find attributes that are true. FIXME catches zero attributes too try idx = find (shp_field); catch warning ("mapshow: rule %d not applicable to atribute %s\n", ... ii-1, rule{1}); end_try_catch elseif (isnumeric (shp_field)) ## Check which shape features have attribute values in the range minr = min (rule{2}); maxr = max (rule{2}); if (ismember (rule{1}, {"X", "Y", "Z", "M"})) ## Multiple attribute values per shape feature (polylines, ...) idx = []; try for jj=1:numel (shp.idx) ## Include all polylines/-gons/multipatches with at least ## one value in the range idx = [idx; (any ( ... shp_field(shp.idx(jj:shp.idx(jj+1)-2)) >= minr & ... shp_field(shp.idx(jj:shp.idx(jj+1)-2)) <= maxr)) ]; endfor catch warning ("mapshow: rule %d not applicable to atribute %s\n", ... ii-1, rule{1}); end_try_catch else ## Single attribute values per shape feature try idx = find (shp_field >= minr & ... shp_field <= maxr); catch warning ("mapshow: rule %d not applicable to atribute %s\n", ... ii-1, rule{1}); end_try_catch endif elseif (iscellstr (shp_field)) ## Match strings try idx = find (strcmp (rule{2}, shp_field)); catch warning ("mapshow: rule %d not applicable to atribute %s\n", ... ii-1, rule{1}); end_try_catch endif ## Plot shape features; but first set up struct vals = zeros(0, 6); jdx = []; for jj=1:numel (idx) jdx = [ jdx ; (size (vals, 1) + 1) ]; vals = [ vals; ... shp.vals(shp.idx(idx(jj)):shp.idx(idx(jj)+1)-2, :); ... NaN(1, 6) ]; endfor vals(end, :) = []; sct.shpbox = shp.shpbox; sct.vals = vals; sct.bbox = shp.bbox(idx, :); sct.npt = shp.npt(idx); sct.npr = shp.npr(idx); sct.idx = jdx; sct.(rule{1}) = shp.(rule{1})(idx); ## Draw results h = shapedraw (sct, rule(3:end){:}); else ## Unrecognized shape type error ("mapshow: improper shape struct type\n"); endif endfor endfor endfunction mapping-1.4.3/inst/PaxHeaders/gpxread.m0000644000000000000000000000006215005124246015016 xustar0020 atime=1746184358 30 ctime=1746184416.655008822 mapping-1.4.3/inst/gpxread.m0000644000175000017500000002327715005124246015345 0ustar00philipphilip## Copyright (C) 2018-2022 Philip Nienhuis ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . ## -*- texinfo -*- ## @deftypefn {} {@var{out} =} gpxread (@var{fname}) ## @deftypefnx {} {@var{out} =} gpxread (@var{fname}, @dots{}) ## Read data from a gpx file. ## ## Input argument @var{fname} (a character string) can be a valid file ## name or a valid URL (the latter experimental). ## ## If no other input arguments are given gpxread will read all data in ## @var{fname} into one output struct @var{out}. The data to be read can ## be selected and/or limited by specifying one or more of the following ## optional property/value pairs (all case-insensitive): ## ## @itemize ## @item "FeatureType' ## This option (a mere "f" suffices) can be one of: ## @table @asis ## @item "WayPoint or simply "w": Read waypoints. ## ## @item "Track" or "t": read tracks. ## ## @item "Route" or "t": read routes. ## ## @item "Auto" or "a" (default value): read all data. ## @end table ## ## Multiple FeatureType property/value pairs can be specified. ## ## @item "Index" ## The ensuing Index value should be a numeric value, or numeric vector, ## of indices of the features to be read. Works currently only for waypoints. ## @end itemize ## ## Output argument @var{out} is a struct array with field names Name, ## Lat, Lon, Ele, Time, and -in case of routes- Names. "Name" refers ## to the name of the waypoints, tracks or routes that have been read. ## "Lat", "Lon" and "Ele" refer to the latitude, longitude and (if present ## in the file) elevation of the various features, in case of tracks field ## "Time" refers to the time of the trackpoint (again, if present in the ## file). In case of tracks and routes these are vectors, each element ## corresponding to one track point. For each individual track multiple ## track segments are separated by NaNs. For routes the field "Names" ## contains a cell array holding the names of the individual route points. ## "Time" fields for waypoints are ignored. ## ## Examples: ## ## @example ## A = gpxread ("trip2.gpx", "feature", "track", "index", 2); ## (which returns data from the second track in file "trip1.gpx") ## @end example ## ## @example ## B = gpxread ("trip2.gpx", "f", "t", "f", "r"); ## (which returns track and route data from file "trip2.gpx") ## @end example ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2017-02-05 function [outp] = gpxread (fname, varargin) ## Input validation if (nargin < 1) print_usage (); elseif (! ischar (fname)) error ("gpread: file name expected for arg 1\n"); elseif (! isempty (cell2mat (cell2mat ... (regexp (fname, '(ftp://|http://|file://)', "tokens"))))) url = true; else [pth, fnm, ext] = fileparts (fname); if (isempty (ext)) fname = [fname ".gpx"]; endif url = false; endif if (nargin < 2) gtr = grt = gpt = 1; else gtr = grt = gpt = 0; endif if (mod (nargin, 2) != 1) error ("gpxread: insufficient nr. of input arguments\n"); endif idx = []; for ii=1:2:numel (varargin) if (ischar (varargin{ii}) && numel (varargin{ii}) > 0) switch lower (varargin{ii})(1) case "f" switch lower (varargin{ii+1})(1) case "t" gtr = 1; case "r" grt = 1; case "w" gpt = 1; case "a" gtr = grt = gpt = 1; otherwise error ("gpxread: unknown FeatureType '%s'", varargin{ii+1}); endswitch case "i" idx = varargin{ii+1}; if (! isnumeric (idx)) error ("gpxread: numeric value or vector expected for arg.# %d\n", ii+1); else idx = uint32 (idx); gpt = 1; endif otherwise warning ("gpxread: unknown option '%s' - ignored\n", varargin{ii}); endswitch else error (["gpxread: wrong argument type for arg. %d - 'FeatureType' or ", ... "'Index' expected"], ii+1); endif endfor if (url) ## Untested xml = urlread (fname); else fid = fopen (fname, "r"); if (fid < 0) error ("gpxread: couldn't open file %s\n", fname); endif xml = fread (fid, Inf, "char=>char")'; fclose (fid); endif outp = repmat (struct ("Type", "-", ... "Lat", [], ... "Lon", [], ... "Ele", [], ... "Time", [], ... "Name", "-"), 0, 1); if (gpt) ## (Try to) Read waypoints ptrnp = 'wpt lat="(.*?)" lon="(.*?)">.*?ele>(.*?)(.*?) size (wpts, 1)) = []; endif [outp(1:numel (idx)).Name] = deal (wpts(idx, 4){:}); [outp(1:numel (idx)).Type] = deal ("WayPoint"); [outp(1:numel (idx)).Lat] = deal (wpts(idx, 1){:}); [outp(1:numel (idx)).Lon] = deal (wpts(idx, 2){:}); [outp(1:numel (idx)).Ele] = deal (wpts(idx, 3){:}); endif endif if (gtr) ## Read tracks ptrnt1A = '(.*?).*?