%% The LaTeX package mercatormap - version 1.3.0 (2026/02/19)
%% mercatormap.sty: geographic coordinates (Mercator projection) and map tiles for TikZ pictures
%%
%% -------------------------------------------------------------------------------------------
%% Copyright (c) 2020-2026 by Prof. Dr. Dr. Thomas F. Sturm <thomas dot sturm at unibw dot de>
%% -------------------------------------------------------------------------------------------
%%
%% This work may be distributed and/or modified under the
%% conditions of the LaTeX Project Public License, either version 1.3
%% of this license or (at your option) any later version.
%% The latest version of this license is in
%%   http://www.latex-project.org/lppl.txt
%% and version 1.3 or later is part of all distributions of LaTeX
%% version 2005/12/01 or later.
%%
%% This work has the LPPL maintenance status `author-maintained'.
%%
%% This work consists of all files listed in README
%%
\NeedsTeXFormat{LaTeX2e}[2023-11-01]
\ProvidesExplPackage{mercatormap}{2026/02/19}{1.3.0}
  {A Web Mercator projection package with map tile support}

\RequirePackage{siunitx,graphicx,tikz}

\ExplSyntaxOff
% space character problem if within explSyntax
\usetikzlibrary{shadings}
\ExplSyntaxOn

%\debug_on:n {all}


\ProvideExpandableDocumentCommand \mrcpkgprefix {}{}

\NewDocumentCommand\mermapset{ m } { \keys_set:nn { mermap } {#1} }
\NewDocumentCommand\mermapsetsupply{ m } { \keys_set:nn { mermap/supply } {#1} }
\NewDocumentCommand\mermapsetmarker{ m } { \keys_set:nn { mermap/marker } {#1} }


%---- scratch variables --------------------------------------------------------

\box_new:N \l__mermap_tmpa_box

\clist_new:N \l__mermap_tmpa_clist

\dim_new:N \l__mermap_tmpa_dim
\dim_new:N \l__mermap_tmpb_dim

\fp_new:N \l__mermap_tmpa_fp
\fp_new:N \l__mermap_tmpb_fp

\tl_new:N \g__mermap_tmpa_tl
\tl_new:N \l__mermap_tmpa_tl
\tl_new:N \l__mermap_tmpb_tl

%---- constants ----------------------------------------------------------------

\fp_const:Nn \c__mermap_scale_radius_fp { 6371*pi/180 }
\fp_const:Nn \c__mermap_mean_radius_fp { 637100000cm }
\fp_const:Nn \c__mermap_mile_fp { 1.609344 }


%---- map definition -----------------------------------------------------------

\dim_new:N \l__mermap_tile_size_dim

\fp_new:N \l__mermap_mapeast_fp
\fp_new:N \l__mermap_mapnorth_fp
\fp_new:N \l__mermap_mapsouth_fp
\fp_new:N \l__mermap_mapwest_fp
\fp_new:N \l__mermap_tex_height_fp
\fp_new:N \l__mermap_tex_width_fp
\fp_new:N \l__mermap_tile_northoffset_fp
\fp_new:N \l__mermap_tile_southoffset_fp
\fp_new:N \l__mermap_tile_westoffset_fp

\int_new:N \l__mermap_tile_xmax_int
\int_new:N \l__mermap_tile_xmin_int
\int_new:N \l__mermap_tile_ymax_int
\int_new:N \l__mermap_tile_ymin_int
\int_new:N \l__mermap_tile_zoom_int

\tl_new:N \l__mermap_attribution_print_tl
\tl_new:N \l__mermap_attribution_tl
\tl_new:N \l__mermap_pixel_height_tl
\tl_new:N \l__mermap_pixel_width_tl
\tl_new:N \l__mermap_tile_basename_tl
\tl_new:N \l__mermap_tile_resource_tl


\keys_define:nn { mermap/mapdef }
  {
    west        .fp_set:N  = \l__mermap_mapwest_fp,
    east        .fp_set:N  = \l__mermap_mapeast_fp,
    north       .fp_set:N  = \l__mermap_mapnorth_fp,
    south       .fp_set:N  = \l__mermap_mapsouth_fp,
    zoom        .int_set:N = \l__mermap_tile_zoom_int,
    xmin        .int_set:N = \l__mermap_tile_xmin_int,
    ymin        .int_set:N = \l__mermap_tile_ymin_int,
    xmax        .int_set:N = \l__mermap_tile_xmax_int,
    ymax        .int_set:N = \l__mermap_tile_ymax_int,
    pixelwidth  .tl_set:N  = \l__mermap_pixel_width_tl,
    pixelheight .tl_set:N  = \l__mermap_pixel_height_tl,
    westoffset  .fp_set:N  = \l__mermap_tile_westoffset_fp,
    northoffset .fp_set:N  = \l__mermap_tile_northoffset_fp,
    southoffset .fp_set:N  = \l__mermap_tile_southoffset_fp,
    basename    .tl_set:N  = \l__mermap_tile_basename_tl,
    resource    .tl_set:N  = \l__mermap_tile_resource_tl,
    attribution .tl_set:N  = \l__mermap_attribution_tl,
    attribution~print .tl_set:N = \l__mermap_attribution_print_tl,
    tile~size   .dim_set:N = \l__mermap_tile_size_dim,
  }


\NewDocumentCommand{\mrcdefinemap}{ m }
  {
    \keys_set:nn { mermap/mapdef }
      {
        west=11,
        east=13,
        north=50,
        south=48,
        zoom=9,
        xmin=271,
        ymin=173,
        xmax=275,
        ymax=177,
        pixelwidth=100,
        pixelheight=100,
        westoffset=0,
        northoffset=0,
        southoffset=0,
        basename=tiles/tile,
        resource=none,
        attribution=,
        attribution~print=,
        #1
      }
    \__mermap_reset:
  }



%---- coordinate system --------------------------------------------------------

\fp_new:N \l__mermap_cs_lat_fp
\fp_new:N \l__mermap_cs_lon_fp
\fp_new:N \l__mermap_cs_southreference_fp
\fp_new:N \l__mermap_cs_x_fp
\fp_new:N \l__mermap_cs_xfactor_fp
\fp_new:N \l__mermap_cs_y_fp
\fp_new:N \l__mermap_cs_yfactor_fp
\fp_new:N \l__mermap_result_fp
\fp_new:N \l__mermap_scale_denominator_fp
\fp_new:N \l__mermap_scale_fp
\fp_new:N \l__mermap_vic_dim_fp
\fp_new:N \l__mermap_vic_east_fp
\fp_new:N \l__mermap_vic_north_fp
\fp_new:N \l__mermap_vic_south_fp
\fp_new:N \l__mermap_vic_west_fp
\fp_new:N \l__mermap_vic_westeast_fp
\fp_new:N \l__mermap_westeast_fp

\int_new:N \l__mermap_tile_number_int


\keys_define:nn { mermap }
  {
    vicinity .fp_set:N = \l__mermap_vic_dim_fp
  }
\keys_set:nn { mermap } { vicinity=2cm }


\NewExpandableDocumentCommand\mrcmapwest{}{\fp_to_decimal:N \l__mermap_mapwest_fp}
\NewExpandableDocumentCommand\mrcmapeast{}{\fp_to_decimal:N \l__mermap_mapeast_fp}
\NewExpandableDocumentCommand\mrcmapnorth{}{\fp_to_decimal:N \l__mermap_mapnorth_fp}
\NewExpandableDocumentCommand\mrcmapsouth{}{\fp_to_decimal:N \l__mermap_mapsouth_fp}
\NewExpandableDocumentCommand\mrcpixelwidth{}{\tl_use:N \l__mermap_pixel_width_tl}
\NewExpandableDocumentCommand\mrcpixelheight{}{\tl_use:N \l__mermap_pixel_height_tl}
\NewDocumentCommand\mrcmapattribution{}{\tl_use:N \l__mermap_attribution_tl}
\NewDocumentCommand\mrcmapattributionprint{}{\tl_use:N \l__mermap_attribution_print_tl}
\NewExpandableDocumentCommand\mrctexwidth{}{\fp_to_dim:N \l__mermap_tex_width_fp}
\NewExpandableDocumentCommand\mrctexheight{}{\fp_to_dim:N \l__mermap_tex_height_fp}
\NewExpandableDocumentCommand\mrcscale{}{\fp_to_decimal:N \l__mermap_scale_fp}
\NewExpandableDocumentCommand\mrcmapscaledenominator{}{\fp_to_decimal:N \l__mermap_scale_denominator_fp}


\cs_new_nopar:Npn \__mermap_reset:
  {
    \int_set:Nn \l__mermap_tile_number_int { \fp_to_int:n { 2^\l__mermap_tile_zoom_int }}
    \fp_set:Nn \l__mermap_westeast_fp    { \l__mermap_mapeast_fp-\l__mermap_mapwest_fp }
    \fp_set:Nn \l__mermap_cs_xfactor_fp  { \l__mermap_tile_size_dim*\l__mermap_tile_number_int/360 }
    \fp_set:Nn \l__mermap_cs_yfactor_fp  { \l__mermap_tile_size_dim*\l__mermap_tile_number_int/2pi }
    \fp_set:Nn \l__mermap_cs_southreference_fp { tand(\l__mermap_mapsouth_fp/2+45) }

    \__mermap_longitude_to_x:n { \l__mermap_mapwest_fp }
    \__mermap_x_to_longitude:n { \l__mermap_cs_x_fp - \l__mermap_vic_dim_fp }
    \fp_set_eq:NN \l__mermap_vic_west_fp \l__mermap_cs_lon_fp

    \__mermap_longitude_to_x:n { \l__mermap_mapeast_fp }
    \__mermap_x_to_longitude:n { \l__mermap_cs_x_fp + \l__mermap_vic_dim_fp }
    \fp_set_eq:NN \l__mermap_vic_east_fp \l__mermap_cs_lon_fp

    \__mermap_latitude_to_y:n { \l__mermap_mapsouth_fp }
    \__mermap_y_to_latitude:n { \l__mermap_cs_y_fp - \l__mermap_vic_dim_fp }
    \fp_set_eq:NN \l__mermap_vic_south_fp \l__mermap_cs_lat_fp

    \__mermap_latitude_to_y:n { \l__mermap_mapnorth_fp }
    \fp_set_eq:NN \l__mermap_tex_height_fp \l__mermap_cs_y_fp
    \__mermap_y_to_latitude:n { \l__mermap_cs_y_fp + \l__mermap_vic_dim_fp }
    \fp_set_eq:NN \l__mermap_vic_north_fp \l__mermap_cs_lat_fp

    \fp_set:Nn \l__mermap_tex_width_fp { \l__mermap_westeast_fp*\l__mermap_cs_xfactor_fp }

    \fp_set:Nn \l__mermap_vic_westeast_fp { \l__mermap_vic_east_fp - \l__mermap_vic_west_fp }

    \__mermap_mean_latitude:NN \l__mermap_mapsouth_fp \l__mermap_mapnorth_fp
    \fp_set:Nn \l__mermap_scale_denominator_fp { 2*\c__mermap_mean_radius_fp
      *cosd(\l__mermap_result_fp)*pi/\l__mermap_tile_number_int/\l__mermap_tile_size_dim }
    \fp_set:Nn \l__mermap_scale_fp { \l__mermap_scale_denominator_fp / (1cm*100000) }

    \__mermap_if_inside_picture_environment:T
      {
        \node[name=mrcmap,at={(0,0)},above~right,
          line~width=0mm,inner~sep=0mm,outer~sep=0mm,draw=none,fill=none,rectangle,
          minimum~width=\mrctexwidth,minimum~height=\mrctexheight]{};
      }
  }


\cs_new_nopar:Npn \__mermap_mean_latitude:NN #1#2
  {
    \fp_set:Nn \l__mermap_result_fp { 2*atand(sqrt(tand(#1/2+45)*tand(#2/2+45))) - 90 }
  }


\cs_new_nopar:Npn \__mermap_longitude_to_x:n #1
  {
    \fp_set:Nn \l__mermap_tmpa_fp { #1-\l__mermap_mapwest_fp }
    \fp_sub:Nn \l__mermap_tmpa_fp { 360*floor(\l__mermap_tmpa_fp/360) }
    \fp_set:Nn \l__mermap_tmpa_fp
      { \l__mermap_tmpa_fp>\l__mermap_westeast_fp
          ?(\l__mermap_tmpa_fp-\l__mermap_westeast_fp>360-\l__mermap_tmpa_fp
            ?\l__mermap_tmpa_fp-360
            :\l__mermap_tmpa_fp)
          :\l__mermap_tmpa_fp
      }
    \fp_set:Nn \l__mermap_cs_x_fp { \l__mermap_tmpa_fp*\l__mermap_cs_xfactor_fp }
  }


\cs_new_nopar:Npn \__mermap_latitude_to_y:n #1
  {
    \fp_set:Nn \l__mermap_cs_y_fp
    {
      ln( tand((#1)/2+45)/\l__mermap_cs_southreference_fp ) * \l__mermap_cs_yfactor_fp
    }
  }


\cs_new_nopar:Npn \__mermap_x_to_longitude:n #1
  {
    \fp_set:Nn \l__mermap_cs_lon_fp { \l__mermap_mapwest_fp+(#1)/\l__mermap_cs_xfactor_fp }
  }


\cs_new_nopar:Npn \__mermap_y_to_latitude:n #1
  {
    \fp_set:Nn \l__mermap_cs_lat_fp
    {
      2*atand( \l__mermap_cs_southreference_fp*exp((#1)/\l__mermap_cs_yfactor_fp) ) - 90
    }
  }


\cs_new_nopar:Npn \__mermap_pgfpoint:nn #1#2
  {
    \__mermap_latitude_to_y:n  {#1}
    \__mermap_longitude_to_x:n {#2}
    \pgfpoint{\fp_to_dim:N \l__mermap_cs_x_fp}
             {\fp_to_dim:N \l__mermap_cs_y_fp}
  }


\use:x
  {
    \cs_new_nopar:Npn \exp_not:N\__mermap_pgfpoint:w ##1 \c_colon_str ##2 \exp_not:N \q_stop
  }
  {
    \__mermap_pgfpoint:nn {#1}{#2}
  }


\cs_new_nopar:Npn \__mermap_pgfpoint:n #1
  {
    \__mermap_pgfpoint:w #1 \q_stop
  }


\NewDocumentCommand{\mrcpgfpoint}{ mm }{ \__mermap_pgfpoint:nn {#1}{#2} }


\keys_define:nn { mermap/cs }
  {
    latitude  .code:n = \__mermap_latitude_to_y:n {#1},
    longitude .code:n = \__mermap_longitude_to_x:n{#1},
    lat       .code:n = \__mermap_latitude_to_y:n {#1},
    lon       .code:n = \__mermap_longitude_to_x:n{#1},
  }


\tikzdeclarecoordinatesystem{__mrc}
  {
    \__mermap_pgfpoint:nn #1
  }


\tikzdeclarecoordinatesystem{mrcq}
  {
    \__mermap_pgfpoint:w #1 \q_stop
  }


\tikzdeclarecoordinatesystem{mrc}%
  {
    \keys_set:nn { mermap/cs }{ #1 }
    \pgfpoint{\fp_to_dim:N \l__mermap_cs_x_fp}
             {\fp_to_dim:N \l__mermap_cs_y_fp}
  }


\prg_new_conditional:Npnn \__mermap_if_in_map:nn #1#2 { p, T, F, TF }
  {
    \fp_compare:nNnTF {#1} > \l__mermap_mapnorth_fp
    {
      \prg_return_false:
    }
    {
      \fp_compare:nNnTF {#1} < \l__mermap_mapsouth_fp
      {
        \prg_return_false:
      }
      {
        \fp_set:Nn \l__mermap_tmpa_fp { #2-\l__mermap_mapwest_fp }
        \fp_sub:Nn \l__mermap_tmpa_fp { 360*floor(\l__mermap_tmpa_fp/360) }
        \fp_compare:nNnTF \l__mermap_tmpa_fp > \l__mermap_westeast_fp
        {
          \prg_return_false:
        }
        {
          \fp_set:Nn \l__mermap_cs_x_fp { \l__mermap_tmpa_fp*\l__mermap_cs_xfactor_fp }
          \__mermap_latitude_to_y:n {#1}
          \pgfnoderename{mrclastpos}{mrcpos}
          \pgfcoordinate{mrcpos}{
            \pgfpoint{\fp_to_dim:N \l__mermap_cs_x_fp}
                     {\fp_to_dim:N \l__mermap_cs_y_fp}
          }
          \prg_return_true:
        }
      }
    }
  }

\NewDocumentCommand{\ifmrcinmap}{ mm }
  {
    \__mermap_if_in_map:nnTF{#1}{#2}
  }


\prg_new_conditional:Npnn \__mermap_if_in_vicinity:nn #1#2 { p, T, F, TF }
  {
    \fp_compare:nNnTF {#1} > \l__mermap_vic_north_fp
    {
      \prg_return_false:
    }
    {
      \fp_compare:nNnTF {#1} < \l__mermap_vic_south_fp
      {
        \prg_return_false:
      }
      {
        \fp_set:Nn \l__mermap_tmpa_fp { #2-\l__mermap_vic_west_fp }
        \fp_sub:Nn \l__mermap_tmpa_fp { 360*floor(\l__mermap_tmpa_fp/360) }
        \fp_compare:nNnTF \l__mermap_tmpa_fp > \l__mermap_vic_westeast_fp
        {
          \prg_return_false:
        }
        {
          \fp_set:Nn \l__mermap_cs_x_fp { \l__mermap_tmpa_fp*\l__mermap_cs_xfactor_fp - \l__mermap_vic_dim_fp }
          \__mermap_latitude_to_y:n {#1}
          \pgfnoderename{mrclastpos}{mrcpos}
          \pgfcoordinate{mrcpos}{
            \pgfpoint{\fp_to_dim:N \l__mermap_cs_x_fp}
                     {\fp_to_dim:N \l__mermap_cs_y_fp}
          }
          \prg_return_true:
        }
      }
    }
  }

\NewDocumentCommand{\ifmrcinvicinity}{ mm }
  {
    \__mermap_if_in_vicinity:nnTF{#1}{#2}
  }




%---- named positions ----------------------------------------------------------


\cs_new_nopar:Npn \__mermap_set_named_position #1#2#3
  {
    \cs_set_nopar:cpx {__mermap__lat__#1} { \fp_to_decimal:n {#2} }
    \cs_set_nopar:cpx {__mermap__lon__#1} { \fp_to_decimal:n {#3} }
  }


\NewDocumentCommand{\mrcNPdef}{ mmm }
  {
    \__mermap_set_named_position{#1}{#2}{#3}
  }


\NewDocumentCommand{\mrcNPfrompoint}{ mm }
  {
    \path (#2);
    \__mermap_y_to_latitude:n {\pgf@y}
    \__mermap_x_to_longitude:n{\pgf@x}
    \__mermap_set_named_position {#1}
      {\fp_to_decimal:N \l__mermap_cs_lat_fp}
      {\fp_to_decimal:N \l__mermap_cs_lon_fp}
  }


\msg_new:nnnn{ mercatormap }{ np-undefined }
  { Named~point~'#1'~is~undefined. }
  {
    The~named~point~'#1'~is~not~known:~
    perhaps~it~is~spelled~incorrectly.
  }


\NewExpandableDocumentCommand \mrcNPlat { m }
  {
    \cs_if_exist_use:cF{ __mermap__lat__#1 }{ 0 }
  }


\NewExpandableDocumentCommand \mrcNPlon { m }
  {
    \cs_if_exist_use:cF{ __mermap__lon__#1 }{ 0 }
  }


\NewExpandableDocumentCommand \mrcNPcs { m }
  {
    __mrc~cs \c_colon_str {{\mrcNPlat{#1}}{\mrcNPlon{#1}}}
  }


\prg_new_conditional:Npnn \__mermap_if_NP_exists:n #1 { p, TF }
  {
    \cs_if_exist:cTF{ __mermap__lat__#1 }
      {
        \cs_if_exist:cTF{ __mermap__lon__#1 }
        {
          \prg_return_true:
        }
        {
          \prg_return_false:
        }
      }
      {
        \prg_return_false:
      }
  }


\NewDocumentCommand{\ifmrcNPexists}{ m }
  {
    \__mermap_if_NP_exists:nTF{ #1 }
  }


\prg_new_conditional:Npnn \__mermap_if_NP_in_map:n #1 { p, TF }
  {
    \__mermap_if_NP_exists:nTF { #1 }
    {
      \__mermap_if_in_map:nnTF{ \mrcNPlat{#1} }{ \mrcNPlon{#1} }
      {
        \prg_return_true:
      }
      {
      \prg_return_false:
      }
    }
    {
      \prg_return_false:
    }
  }


\NewDocumentCommand{\ifmrcNPinmap}{ m }
  {
    \__mermap_if_NP_in_map:nTF { #1 }
  }


\prg_new_conditional:Npnn \__mermap_if_NP_in_vicinity:n #1 { p, TF }
  {
    \__mermap_if_NP_exists:nTF { #1 }
    {
      \__mermap_if_in_vicinity:nnTF{ \mrcNPlat{#1} }{ \mrcNPlon{#1} }
      {
        \prg_return_true:
      }
      {
      \prg_return_false:
      }
    }
    {
      \prg_return_false:
    }
  }


\NewDocumentCommand{\ifmrcNPinvicinity}{ m }
  {
    \__mermap_if_NP_in_vicinity:nTF{ #1 }
  }



%---- map tile download --------------------------------------------------------

\group_begin:
\char_set_catcode_space:n {`\ }
\char_set_catcode_other:n {`\"}

\tl_const:Nn \c__mermap_supply_call_boundaries_tl
  {
    \l__mermap_python_tl\c_space_tl boundaries
      -u   "\str_use:N\l__mermap_supply_url_str"
      -at  "\str_use:N\l__mermap_supply_attribution_str"
      -atp "\str_use:N\l__mermap_supply_attribution_print_str"
      -f   "\l__mermap_supply_basename_tl"
      -z    \int_use:N\l__mermap_supply_zoom_int\c_space_tl
      -w    \fp_use:N\l__mermap_supply_west_fp\c_space_tl
      -e    \fp_use:N\l__mermap_supply_east_fp\c_space_tl
      -n    \fp_use:N\l__mermap_supply_north_fp\c_space_tl
      -s    \fp_use:N\l__mermap_supply_south_fp\c_space_tl
      -p    \l__mermap_supply_pixel_tl\c_space_tl
      -ts   \dim_use:N\l__mermap_tile_size_dim\c_space_tl
      -t    \l__mermap_supply_target_tl\c_space_tl
      -d   "\str_use:N\l__mermap_definition_id_str"
  }

\tl_const:Nn \c__mermap_supply_call_reference_tl
  {
    \l__mermap_python_tl\c_space_tl reference
      -u   "\str_use:N\l__mermap_supply_url_str"
      -at  "\str_use:N\l__mermap_supply_attribution_str"
      -atp "\str_use:N\l__mermap_supply_attribution_print_str"
      -f   "\l__mermap_supply_basename_tl"
      -mw   \fp_use:N\l__mermap_supply_width_fp\c_space_tl
      -mh   \fp_use:N\l__mermap_supply_height_fp\c_space_tl
      -z    \int_use:N\l__mermap_supply_zoom_int\c_space_tl
      -lat  \fp_use:N\l__mermap_supply_latitude_fp\c_space_tl
      -lon  \fp_use:N\l__mermap_supply_longitude_fp\c_space_tl
      -a    \l__mermap_supply_align_tl\c_space_tl
      -p    \l__mermap_supply_pixel_tl\c_space_tl
      -ts   \dim_use:N\l__mermap_tile_size_dim\c_space_tl
      -t    \l__mermap_supply_target_tl\c_space_tl
      -d   "\str_use:N\l__mermap_definition_id_str"
  }


\tl_const:Nn \c__mermap_supply_call_areafit_tl
  {
    \l__mermap_python_tl\c_space_tl areafit
      -u   "\str_use:N\l__mermap_supply_url_str"
      -at  "\str_use:N\l__mermap_supply_attribution_str"
      -atp "\str_use:N\l__mermap_supply_attribution_print_str"
      -f   "\l__mermap_supply_basename_tl"
      -mw   \fp_use:N\l__mermap_supply_width_fp\c_space_tl
      -mh   \fp_use:N\l__mermap_supply_height_fp\c_space_tl
      -w    \fp_use:N\l__mermap_supply_west_fp\c_space_tl
      -e    \fp_use:N\l__mermap_supply_east_fp\c_space_tl
      -n    \fp_use:N\l__mermap_supply_north_fp\c_space_tl
      -s    \fp_use:N\l__mermap_supply_south_fp\c_space_tl
      -a    \l__mermap_supply_align_tl\c_space_tl
      -p    \l__mermap_supply_pixel_tl\c_space_tl
      -ts   \dim_use:N\l__mermap_tile_size_dim\c_space_tl
      -t    \l__mermap_supply_target_tl\c_space_tl
      -d   "\str_use:N\l__mermap_definition_id_str"
  }

\group_end:


\bool_new:N \l__mermap_script_activated_bool
\bool_new:N \l__mermap_fail_on_missing_resource_bool

\fp_new:N \l__mermap_supply_east_fp
\fp_new:N \l__mermap_supply_height_fp
\fp_new:N \l__mermap_supply_latitude_fp
\fp_new:N \l__mermap_supply_longitude_fp
\fp_new:N \l__mermap_supply_north_fp
\fp_new:N \l__mermap_supply_south_fp
\fp_new:N \l__mermap_supply_west_fp
\fp_new:N \l__mermap_supply_width_fp

\int_new:N \g__mermap_automap_int
\int_new:N \l__mermap_supply_zoom_int

\iow_new:N \l__mermap_iow

\prop_new:N \g__mermap_apikey_prop
\prop_new_linked:N \g__mermap_definition_prop

\str_new:N \l__mermap_definition_id_str
\str_new:N \l__mermap_definition_postfix_str
\str_new:N \l__mermap_definition_prefix_str
\str_new:N \l__mermap_supply_attribution_print_str
\str_new:N \l__mermap_supply_attribution_str
\str_new:N \l__mermap_supply_url_str

\tl_new:N \l__mermap_last_mdfivesum_tl
\tl_new:N \l__mermap_mdfivesum_tl
\tl_new:N \l__mermap_python_tl
\tl_new:N \l__mermap_supply_align_tl
\tl_new:N \l__mermap_supply_basename_tl
\tl_new:N \l__mermap_supply_call_tl
\tl_new:N \l__mermap_supply_pixel_tl
\tl_new:N \l__mermap_supply_target_tl
\tl_new:N \l__mermap_supply_type_tl


\use:x
  {
    \cs_new_nopar:Npn \exp_not:N\__mermap_supply_position:w ##1 \c_colon_str ##2 \exp_not:N \q_stop
  }
  {
    \fp_set:Nn \l__mermap_supply_latitude_fp {#1}
    \fp_set:Nn \l__mermap_supply_longitude_fp {#2}
  }


\msg_new:nnnn{ mercatormap }{ api-key-undefined }
  { Api~key~'#1'~is~undefined. }
  {
    You~have~to~set~\token_to_str:N \mrcsetapikey
      \iow_char:N \{#1\iow_char:N \}
      \iow_char:N \{your~key\iow_char:N \}~first.
  }

\cs_new:Npn \__mermap_supply_url_with_api_key:nnn #1#2#3
  {
    \str_set:Nn \l__mermap_supply_url_str {#1}
    \prop_get:NnNF \g__mermap_apikey_prop {#2} \l__mermap_tmpa_tl
      {
        \msg_error:nnx{ mercatormap }{ api-key-undefined }{ #2 }
      }
    \str_put_right:NV \l__mermap_supply_url_str \l__mermap_tmpa_tl
    \str_put_right:Nn \l__mermap_supply_url_str {#3}
  }


\cs_new:Npn \__mermap_supply_add_area_clist:N #1
  {
    \clist_map_inline:Nn #1
      {
        \cs_if_exist:cF{__mermap__lat__##1}
        {
          \msg_error:nnx{ mercatormap }{ np-undefined }{ ##1 }
        }
        \fp_set:Nn \l__mermap_tmpa_fp { \mrcNPlat{##1} }
        \fp_compare:nNnT \l__mermap_tmpa_fp < \l__mermap_supply_south_fp
          { \fp_set_eq:NN \l__mermap_supply_south_fp \l__mermap_tmpa_fp }
        \fp_compare:nNnT \l__mermap_tmpa_fp > \l__mermap_supply_north_fp
          { \fp_set_eq:NN \l__mermap_supply_north_fp \l__mermap_tmpa_fp }
        \fp_set:Nn \l__mermap_tmpa_fp { \mrcNPlon{##1} }
        \fp_compare:nNnT \l__mermap_tmpa_fp < \l__mermap_supply_west_fp
          { \fp_set_eq:NN \l__mermap_supply_west_fp \l__mermap_tmpa_fp }
        \fp_compare:nNnT \l__mermap_tmpa_fp > \l__mermap_supply_east_fp
          { \fp_set_eq:NN \l__mermap_supply_east_fp \l__mermap_tmpa_fp }
      }
  }


\msg_new:nnn { mercatormap }{ input-area-marker }
  { The~marker~input~file~'#1'~does~not~exist. }

\cs_new:Npn \__mermap_supply_add_area_marker_position:
  {
    \fp_compare:nNnT \l__mermap_marker_latitude_fp < \l__mermap_supply_south_fp
      { \fp_set_eq:NN \l__mermap_supply_south_fp \l__mermap_marker_latitude_fp }
    \fp_compare:nNnT \l__mermap_marker_latitude_fp > \l__mermap_supply_north_fp
      { \fp_set_eq:NN \l__mermap_supply_north_fp \l__mermap_marker_latitude_fp }
    \fp_compare:nNnT \l__mermap_marker_longitude_fp < \l__mermap_supply_west_fp
      { \fp_set_eq:NN \l__mermap_supply_west_fp \l__mermap_marker_longitude_fp }
    \fp_compare:nNnT \l__mermap_marker_longitude_fp > \l__mermap_supply_east_fp
      { \fp_set_eq:NN \l__mermap_supply_east_fp \l__mermap_marker_longitude_fp }
  }

\cs_new:Npn \__mermap_supply_add_area_marker:n #1
  {
    \group_begin:
      \RenewDocumentCommand \mrcmarker { m }
        {
          \keys_set:nn { mermap/marker } { ##1 }
          \__mermap_supply_add_area_marker_position:
        }
      \file_if_exist_input:nF {#1}
        {
          \msg_error:nnn { mercatormap }{ input-area-marker }{ #1 }
        }
      \tl_gset:Nx \g__mermap_tmpa_tl
        {
          \exp_not:N\fp_set:Nn \exp_not:N\l__mermap_supply_west_fp  { \fp_to_decimal:N\l__mermap_supply_west_fp }
          \exp_not:N\fp_set:Nn \exp_not:N\l__mermap_supply_east_fp  { \fp_to_decimal:N\l__mermap_supply_east_fp }
          \exp_not:N\fp_set:Nn \exp_not:N\l__mermap_supply_south_fp { \fp_to_decimal:N\l__mermap_supply_south_fp }
          \exp_not:N\fp_set:Nn \exp_not:N\l__mermap_supply_north_fp { \fp_to_decimal:N\l__mermap_supply_north_fp }
        }
      \group_insert_after:N \g__mermap_tmpa_tl
    \group_end:
  }


\keys_define:nn { mermap/supply }
  {
    zoom            .int_set:N = \l__mermap_supply_zoom_int,
    west            .fp_set:N  = \l__mermap_supply_west_fp,
    east            .fp_set:N  = \l__mermap_supply_east_fp,
    north           .fp_set:N  = \l__mermap_supply_north_fp,
    south           .fp_set:N  = \l__mermap_supply_south_fp,
    latitude        .fp_set:N  = \l__mermap_supply_latitude_fp,
    longitude       .fp_set:N  = \l__mermap_supply_longitude_fp,
    position        .code:n    = {\__mermap_supply_position:w #1 \q_stop},
    named~position  .meta:nn   = {mermap/supply}{latitude=\mrcNPlat{#1},longitude=\mrcNPlon{#1}},
    width           .fp_set:N  = \l__mermap_supply_width_fp,
    height          .fp_set:N  = \l__mermap_supply_height_fp,
    align           .tl_set:N  = \l__mermap_supply_align_tl,
    url             .code:n    = {\str_set:Nn\l__mermap_supply_url_str {#1}},
    url~with~api~key  .code:n  = {\__mermap_supply_url_with_api_key:nnn #1},
    basename        .tl_set:N  = \l__mermap_supply_basename_tl,
    type            .tl_set:N  = \l__mermap_supply_type_tl,
    target          .tl_set:N  = \l__mermap_supply_target_tl,
    pixel           .tl_set:N  = \l__mermap_supply_pixel_tl,
    attribution     .code:n    = {
        \str_set:Nn \l__mermap_supply_attribution_str {#1}
        \tl_set_rescan:Nnn \l__mermap_attribution_tl {}{#1}
      },
    attribution~print .code:n =  {
        \str_set:Nn \l__mermap_supply_attribution_print_str {#1}
        \tl_set_rescan:Nnn \l__mermap_attribution_print_tl {}{#1}
      },
    dpi .code:n = {
      \tl_set:Nx \l__mermap_supply_pixel_tl {
        \fp_to_int:n { round(#1*\l__mermap_tile_size_dim/1in) }
      }},
    tex~width .code:n = {
      \fp_set:Nn \l__mermap_supply_width_fp{#1/\l__mermap_tile_size_dim}},
    tex~height .code:n = {
      \fp_set:Nn \l__mermap_supply_height_fp{#1/\l__mermap_tile_size_dim}},
    source .code:n = { \exp_args:Nnx \keys_set:nn {mermap/supply} {_source=#1} },
    source .value_required:n = true,
    _source .choice:,
    area .code:n =
    {
      \clist_set:Nn \l__mermap_tmpa_clist { #1 }
      \fp_set:Nn \l__mermap_supply_west_fp { inf }
      \fp_set:Nn \l__mermap_supply_east_fp { -inf }
      \fp_set:Nn \l__mermap_supply_south_fp { 89 }
      \fp_set:Nn \l__mermap_supply_north_fp { -89 }
      \__mermap_supply_add_area_clist:N \l__mermap_tmpa_clist
    },
    area .value_required:n = true,
    add~area .code:n =
    {
      \clist_set:Nn \l__mermap_tmpa_clist { #1 }
      \__mermap_supply_add_area_clist:N \l__mermap_tmpa_clist
    },
    area~from~marker~input .code:n =
    {
      \fp_set:Nn \l__mermap_supply_west_fp { inf }
      \fp_set:Nn \l__mermap_supply_east_fp { -inf }
      \fp_set:Nn \l__mermap_supply_south_fp { 89 }
      \fp_set:Nn \l__mermap_supply_north_fp { -89 }
      \__mermap_supply_add_area_marker:n { #1 }
    },
    area~from~marker~input .value_required:n = true,
    add~area~from~marker~input .code:n =
    {
      \__mermap_supply_add_area_marker:n { #1 }
    },
    flex~reference~scale .code:n = {
      \__mermap_set_flex_scale:nn {#1} {\l__mermap_supply_latitude_fp}
      },
    flex~reference~scale .value_required:n = true,
    area~to~reference  .code:n = {
      \fp_set:Nn \l__mermap_supply_longitude_fp { (\l__mermap_supply_west_fp+\l__mermap_supply_east_fp)/2 }
      \__mermap_mean_latitude:NN \l__mermap_supply_north_fp \l__mermap_supply_south_fp
      \fp_set_eq:NN \l__mermap_supply_latitude_fp \l__mermap_result_fp
    },
    area~to~reference .value_forbidden:n = true,
    flex~area~scale   .meta:nn = {mermap/supply}{area~to~reference,flex~reference~scale={#1}},
    flex~area~scale   .value_required:n = true,
    flex~area~fit .code:n = {
      \fp_compare:nNnF \l__mermap_tile_size_dim = \l__mermap_flex_tile_size_dim
        {
          \fp_set:Nn \l__mermap_tmpa_fp { \l__mermap_tile_size_dim/\l__mermap_flex_tile_size_dim }
          \fp_set:Nn \l__mermap_supply_width_fp{\l__mermap_supply_width_fp*\l__mermap_tmpa_fp}
          \fp_set:Nn \l__mermap_supply_height_fp{\l__mermap_supply_height_fp*\l__mermap_tmpa_fp}
        }
      \fp_set:Nn \l__mermap_supply_width_fp{\l__mermap_supply_width_fp-(#1)/\l__mermap_flex_tile_size_dim}
      \fp_set:Nn \l__mermap_supply_height_fp{\l__mermap_supply_height_fp-(#1)/\l__mermap_flex_tile_size_dim}
      \fp_set:Nn \l__mermap_tmpa_fp { min ( 180*\l__mermap_supply_width_fp / (\l__mermap_supply_east_fp-\l__mermap_supply_west_fp)
        , pi*\l__mermap_supply_height_fp / ln( tand(\l__mermap_supply_north_fp/2+45) / tand(\l__mermap_supply_south_fp/2+45) ) ) }
      \fp_set:Nn \l__mermap_tmpb_fp { ln(\l__mermap_tmpa_fp)/ln(2) }
      \fp_set:Nn \l__mermap_tmpb_fp { round(\l__mermap_tmpb_fp)/\l__mermap_tmpb_fp }
      \fp_set:Nn \l__mermap_tmpb_fp { \l__mermap_tmpa_fp^(\l__mermap_tmpb_fp-1+0.0000001) }
      \dim_set:Nn \l__mermap_tile_size_dim { \fp_to_dim:n { \l__mermap_flex_tile_size_dim / \l__mermap_tmpb_fp }}
      \fp_set:Nn \l__mermap_supply_width_fp { \l__mermap_supply_width_fp * \l__mermap_tmpb_fp + (#1)/\l__mermap_tile_size_dim }
      \fp_set:Nn \l__mermap_supply_height_fp { \l__mermap_supply_height_fp * \l__mermap_tmpb_fp + (#1)/\l__mermap_tile_size_dim }
    },
    flex~area~fit .default:n = 0pt,
  }


\keys_set:nn { mermap/supply }
  {
    zoom=9,
    north=50,
    south=48,
    west=11,
    east=13,
    latitude=49,
    longitude=12,
    width=4,
    height=4,
    align=center,
    basename=tiles/tile,
    url=,
    attribution=,
    attribution~print=,
    type=reference,
    pixel=256,
    target=tiles,
  }


\keys_define:nn { mermap }
  {
    definition~prefix .code:n            = {\str_set:Nn\l__mermap_definition_prefix_str{#1}},
    fail~on~missing~resource .bool_set:N = \l__mermap_fail_on_missing_resource_bool,
    python              .code:n = {
      \tl_set:Nx \l__mermap_python_tl {#1~maptiles.texpy}
      },
  }

\keys_set:nn { mermap }
  {
    definition~prefix = maps/,
    fail~on~missing~resource = true,
    python = python,
  }


\msg_new:nnn { mercatormap }{ python-script }
  { Python~script~'maptiles.texpy'~is~created~for~map~tile~download. }


\NewDocumentCommand \mrcactivatescript {}
  {
    \msg_info:nn { mercatormap }{ python-script }
    \file_input:n {\mrcpkgprefix mercatorpy.def}
    \bool_set_true:N \l__mermap_script_activated_bool
  }
\@onlypreamble\mrcactivatescript


\NewDocumentCommand \mrcsetapikey { mm }
  {
     \prop_gput:Nnn \g__mermap_apikey_prop {#1}{#2}
  }


\cs_new:Npn \__mermap_create_definition_id:n #1
  {
    \tl_set:Nx \l__mermap_tmpa_tl {#1}
    \tl_trim_spaces:N \l__mermap_tmpa_tl
    \str_set:Nx \l__mermap_definition_postfix_str {\tl_to_str:N \l__mermap_tmpa_tl}
    \str_concat:NNN \l__mermap_definition_id_str
      \l__mermap_definition_prefix_str \l__mermap_definition_postfix_str
  }

\cs_new:Npn \__mermap_map:nn #1#2
  {
    \tl_set:Nx \l__mermap_tmpa_tl {#2}
    \tl_trim_spaces:N \l__mermap_tmpa_tl
    \tl_if_empty:NT \l__mermap_tmpa_tl
      {
        \int_gincr:N \g__mermap_automap_int
        \tl_set:Nx \l__mermap_tmpa_tl
          {
            automap-
            \int_compare:nNnTF \g__mermap_automap_int<{10} {000}
            {
              \int_compare:nNnTF \g__mermap_automap_int<{100} {00}
              {
                \int_compare:nNnTF \g__mermap_automap_int<{1000} {0} {}
              }
            }
            \int_use:N \g__mermap_automap_int
          }
      }
    \exp_args:NV \__mermap_create_definition_id:n \l__mermap_tmpa_tl
    %\str_set:Nx \l__mermap_definition_postfix_str {\tl_to_str:N \l__mermap_tmpa_tl}
    %\str_concat:NNN \l__mermap_definition_id_str
    %  \l__mermap_definition_prefix_str \l__mermap_definition_postfix_str
    \__mermap_supplymap:n {#1}
    \__mermap_applymap:
  }

\NewDocumentCommand \mrcmap { O{} m }
  {
    \__mermap_map:nn {#1}{#2}
  }


\msg_new:nnn{ mercatormap }{ definition-id-used }
  { Map~definition~'#1'~already~existing }


\cs_new:Npn \__mermap_supplymap:n #1
  {
    \group_begin:
    \keys_set:nn { mermap/supply } { #1 }
    \prop_if_in:NVT \g__mermap_definition_prop \l__mermap_definition_id_str
      {
        \msg_warning:nnx { mercatormap }{ definition-id-used }{ \str_use:N \l__mermap_definition_id_str }
      }
    \prop_gput:NVn \g__mermap_definition_prop \l__mermap_definition_id_str {}
    \bool_if:NT \l__mermap_script_activated_bool
    {
      \__mermap_supplymap_call:
    }
    \group_end:
  }

\NewDocumentCommand \mrcsupplymap { O{} m }
  {
    \__mermap_create_definition_id:n {#2}
    \__mermap_supplymap:n {#1}
  }


\msg_new:nnnn { mercatormap }{ shell-escape }
  { You~must~invoke~LaTeX~with~the~--shell-escape~flag~to~produce~map~'#1'. }
  { The~--shell-escape~flag~is~needed,~because~a~Python~sript~has~to~be~called;~see~package~documentation. }

\msg_new:nnnn { mercatormap }{ target-resource }
  { Target~and~produced~resource~are~different~for~map~'#1'. }
  { Your~target~was~'\l__mermap_supply_target_tl'.\\
    The~produced~resource~is~'\l__mermap_tile_resource_tl'.\\
    Check,~if~'\l__mermap_supply_target_tl'~is~available~via~'\str_use:N\l__mermap_supply_url_str'\\
    or~if~the~zoom~value~is~too~large.
  }

\msg_new:nnnn { mercatormap }{ definition-production }
  { Map~definition~file~not~produced~for~map~'#1'. }
  { **~The~failed~shell~command~was:\\
    \l__mermap_supply_call_tl\\
    **~Python~setup~correct?
  }

\cs_new:Npn \__mermap_supplymap_call:
  {
    \tl_set_eq:Nc \l__mermap_tmpa_tl {
      c__mermap_supply_call_\l__mermap_supply_type_tl _tl }
    \tl_set:Nx \l__mermap_supply_call_tl \l__mermap_tmpa_tl
    \tl_set:Nx \l__mermap_mdfivesum_tl { \str_mdfive_hash:e{\l__mermap_supply_call_tl} }
    \file_if_exist:nTF {\l__mermap_definition_id_str.def}
      {
        \tl_clear:N \l__mermap_last_mdfivesum_tl
        \file_if_exist_input:n {\l__mermap_definition_id_str.md5}
        \str_if_eq:VVF \l__mermap_mdfivesum_tl \l__mermap_last_mdfivesum_tl
          {
            \__mermap_supplymap_call_shell:
          }
      }
      {
        \__mermap_supplymap_call_shell:
      }
  }

\cs_new:Npn \__mermap_supplymap_call_shell:
  {
    \sys_if_shell_unrestricted:TF
      {
        \file_if_exist:nT {\l__mermap_definition_id_str.def}
          {
            \iow_open:Nn \l__mermap_iow {\l__mermap_definition_id_str.def}
            \iow_now:Nx  \l__mermap_iow {\c_backslash_str def \c_backslash_str mrcdefinemap{} \c_percent_str}
            \iow_close:N \l__mermap_iow
          }

        \sys_shell_now:x {\l__mermap_supply_call_tl}

        \file_if_exist:nTF {\l__mermap_definition_id_str.def}
          {
            \file_input:n {\l__mermap_definition_id_str.def}
            \str_if_eq:VVTF \l__mermap_supply_target_tl \l__mermap_tile_resource_tl
              {
                \__mermap_write_mdfive:n {\l__mermap_mdfivesum_tl}
              }
              {
                \__mermap_write_mdfive:n {false}
                \bool_if:NTF \l__mermap_fail_on_missing_resource_bool
                  {
                    \msg_error:nnx { mercatormap }{ target-resource }{ \l__mermap_definition_id_str }
                  }
                  {
                    \msg_warning:nnx { mercatormap }{ target-resource }{ \l__mermap_definition_id_str }
                  }
              }
          }
          {
            \msg_error:nnx { mercatormap }{ definition-production }{ \l__mermap_definition_id_str }
          }
      }
      {
        \msg_error:nnx { mercatormap }{ shell-escape }{ \l__mermap_definition_id_str }
      }
  }

\NewDocumentCommand \mermaplastfivesum { m }
{
  \tl_set:Nx \l__mermap_last_mdfivesum_tl { #1 }
}

\cs_new:Npn \__mermap_write_mdfive:n #1
  {
    \iow_open:Nn \l__mermap_iow {\l__mermap_definition_id_str.md5}
    \iow_now:Nx  \l__mermap_iow {\c_backslash_str mermaplastfivesum{#1} \c_percent_str}
    \iow_close:N \l__mermap_iow
  }



%---- map drawing --------------------------------------------------------------


\dim_new:N \l__mermap_flex_tile_size_dim
\dim_new:N \l__mermap_tx_dim
\dim_new:N \l__mermap_ty_dim

\int_new:N \l__mermap_tile_x_int
\int_new:N \l__mermap_tile_xmod_int
\int_new:N \l__mermap_tile_y_int

\tl_new:N \l__mermap_current_map_tl
\tl_new:N \l__mermap_draw_map_tl
\tl_new:N \l__mermap_tikz_map_clip_tl
\tl_new:N \l__mermap_tile_filename_tl


\prg_new_conditional:Npnn \__mermap_if_inside_picture_environment: { p, TF, T }
  {
    \cs_if_exist:NTF \pgfpictureid
    {
      \prg_return_true:
    }
    {
      \prg_return_false:
    }
  }



\cs_new_nopar:Npn \__mermap_set_flex_scale:nn  #1#2
  {
    \fp_set:Nn \l__mermap_tmpa_fp { 1+ln(\c__mermap_mean_radius_fp/#1*cosd(#2)*pi/\l__mermap_flex_tile_size_dim)/ln(2) }
    \keys_set:nn { mermap }{ flex~zoom=\l__mermap_tmpa_fp }
  }

\use:x
  {
    \cs_new_nopar:Npn \exp_not:N\__mermap_set_flex_scale:w ##1 \c_colon_str ##2 \exp_not:N \q_stop
  }
  {
    \__mermap_set_flex_scale:nn {#1}{#2}
  }

\use:x
  {
    \cs_new_nopar:Npn \exp_not:N\__mermap_set_named_flex_scale:w ##1 \c_colon_str ##2 \exp_not:N \q_stop
  }
  {
    \__mermap_set_flex_scale:nn {#1}{\mrcNPlat{#2}}
  }


\keys_define:nn { mermap }
  {
    tile~size      .dim_set:N = \l__mermap_tile_size_dim,
    flex~tile~size .dim_set:N = \l__mermap_flex_tile_size_dim,
    flex~zoom      .code:n =
      {
        \int_set:Nn \l__mermap_supply_zoom_int {\fp_to_int:n{round(#1)}}
        \dim_set:Nn \l__mermap_tile_size_dim {\fp_to_dim:n{\l__mermap_flex_tile_size_dim*2^(#1-\l__mermap_supply_zoom_int)}}
      },
    flex~scale        .code:n = {\__mermap_set_flex_scale:w #1 \q_stop},
    named~flex~scale  .code:n = {\__mermap_set_named_flex_scale:w #1 \q_stop},
    map~clip        .tl_set:N = \l__mermap_tikz_map_clip_tl,
    map~scope         .code:n = {\tikzset{mermap_scope_style/.style={#1}}},
    map~path          .code:n = {\tikzset{mermap_path_style/.style={#1}}},
    draw           .tl_set:N = \l__mermap_draw_map_tl,
  }


\keys_set:nn { mermap }
  {
    tile~size      = 32.512mm,
    flex~tile~size = 32.512mm,
    map~clip=\mrcclipmap,
    draw=auto,
    map~scope=,
    map~path={upper~left=green!50, upper~right=green!25,
      lower~left=green!50!black!50, lower~right=green!25},
  }


\NewDocumentCommand \mrcclipmap {}
  {\path[clip] (mrcmap.south~west) rectangle (mrcmap.north~east);}

\NewDocumentCommand \mrcboundmap {}
  {\path[use~as~bounding~box] (mrcmap.south~west) rectangle (mrcmap.north~east);}


\cs_new_nopar:Npn \__mermap_drawmap_path:
  {
    \begin{scope}[
      xshift=\fp_to_dim:n{ (0.5-\l__mermap_tile_westoffset_fp)*\l__mermap_tile_size_dim },
      yshift=\fp_to_dim:n{ (0.5-\l__mermap_tile_southoffset_fp)*\l__mermap_tile_size_dim },
      mermap_scope_style]
    \tl_use:N \l__mermap_tikz_map_clip_tl
    \path[mermap_path_style] (mrcmap.south~west) rectangle (mrcmap.north~east);
    \end{scope}
  }


\cs_new_nopar:Npn \__mermap_drawtile:
  {
    \tl_set:Nx \l__mermap_tile_filename_tl
      {
        \exp_not:o\l__mermap_tile_basename_tl
        _\int_use:N\l__mermap_tile_zoom_int
        _\int_use:N\l__mermap_tile_xmod_int
        _\int_use:N\l__mermap_tile_y_int
        .png
      }
    \file_if_exist:nTF \l__mermap_tile_filename_tl
      {
        \node[line~width=0mm,inner~sep=0mm,outer~sep=0mm,draw=none,fill=none,rectangle]
          at (\l__mermap_tx_dim,\l__mermap_ty_dim)
          {\includegraphics[width=\l__mermap_tile_size_dim]{\l__mermap_tile_filename_tl}};
      }
      {
        \path[mermap_path_style] (\l__mermap_tx_dim,\l__mermap_ty_dim)
          ++(-\l__mermap_tile_size_dim/2,-\l__mermap_tile_size_dim/2)
          rectangle +(\l__mermap_tile_size_dim,\l__mermap_tile_size_dim);
      }
  }


\cs_new_nopar:Npn \__mermap_drawmap_tiles:
  {
    \begin{scope}[
      xshift=\fp_to_dim:n{ (0.5-\l__mermap_tile_westoffset_fp)*\l__mermap_tile_size_dim },
      yshift=\fp_to_dim:n{ (0.5-\l__mermap_tile_southoffset_fp)*\l__mermap_tile_size_dim },
      mermap_scope_style]
    \tl_use:N \l__mermap_tikz_map_clip_tl
    \int_set_eq:NN \l__mermap_tile_x_int \l__mermap_tile_xmin_int
    \dim_set:Nn \l__mermap_tx_dim {0pt}
    \int_until_do:nNnn  \l__mermap_tile_x_int > \l__mermap_tile_xmax_int
      {
        \dim_set:Nn \l__mermap_ty_dim {0pt}
        \int_set:Nn \l__mermap_tile_xmod_int {\int_mod:nn{\l__mermap_tile_x_int}{\l__mermap_tile_number_int}}
        \int_compare:nNnT \l__mermap_tile_xmod_int < 0
          {
            \int_add:Nn \l__mermap_tile_xmod_int \l__mermap_tile_number_int
          }
        \int_set_eq:NN \l__mermap_tile_y_int \l__mermap_tile_ymax_int
        \int_until_do:nNnn  \l__mermap_tile_y_int < \l__mermap_tile_ymin_int
        {
          \int_compare:nNnF \l__mermap_tile_y_int < 0
            {
              \int_compare:nNnT \l__mermap_tile_y_int < \l__mermap_tile_number_int
              {
                \__mermap_drawtile:
              }
            }
          \dim_add:Nn \l__mermap_ty_dim \l__mermap_tile_size_dim
          \int_decr:N \l__mermap_tile_y_int
        }
        \dim_add:Nn \l__mermap_tx_dim \l__mermap_tile_size_dim
        \int_incr:N \l__mermap_tile_x_int
      }
    \end{scope}
  }


\cs_new_nopar:Npn \__mermap_drawsinglemap:
  {
    \begin{scope}[mermap_scope_style]
    \tl_use:N \l__mermap_tikz_map_clip_tl
    \node[above~right,line~width=0mm,inner~sep=0mm,outer~sep=0mm,draw=none,fill=none,rectangle] at (0,0)
      {\includegraphics[width=\mrctexwidth,height=\mrctexheight]{\l__mermap_definition_id_str.png}};
    \end{scope}
  }


\cs_new_nopar:Npn \__mermap_drawmap_mergedmap:
  {
    \str_if_eq:VnTF \l__mermap_tile_resource_tl {mergedmap}
      {
        \__mermap_drawsinglemap:
      }
      {
        \__mermap_drawmap_path:
      }
  }


\cs_new_nopar:Npn \__mermap_drawmap_wmsmap:
  {
    \str_if_eq:VnTF \l__mermap_tile_resource_tl {wmsmap}
      {
        \__mermap_drawsinglemap:
      }
      {
        \__mermap_drawmap_path:
      }
  }


\msg_new:nnn{ mercatormap }{ draw-auto }
  { 'draw=auto' -> 'draw=#1'~is~undefined. }


\cs_new_nopar:Npn \__mermap_drawmap_auto:
  {
    \cs_if_exist:cTF {__mermap_drawmap_\l__mermap_tile_resource_tl :}
      {
        \use:c {__mermap_drawmap_\l__mermap_tile_resource_tl :}
      }
      {
        \str_if_eq:VnTF \l__mermap_tile_resource_tl {none}
          {
            \__mermap_drawmap_path:
          }
          {
            \msg_warning:nnx { mercatormap }{ draw-undefined }{ \tl_use:N \l__mermap_tile_resource_tl }
          }
      }
  }


\msg_new:nnnn{ mercatormap }{ draw-undefined }
  { 'draw=#1'~is~undefined. }
  {
    The~option~value~'#1'~is~not~known~for~'draw':
    perhaps~it~is~spelled~incorrectly.
  }

\NewDocumentCommand \mrcdrawmap { o }
  {
    \group_begin:
    \IfNoValueF {#1}
      { \keys_set:nn { mermap } {#1} }
    \cs_if_exist:cTF {__mermap_drawmap_\l__mermap_draw_map_tl :}
      {
        \use:c {__mermap_drawmap_\l__mermap_draw_map_tl :}
      }
      {
        \msg_warning:nnx { mercatormap }{ draw-undefined }{ \tl_use:N \l__mermap_draw_map_tl }
      }
    \group_end:
  }


\cs_new_nopar:Npn \__mermap_applymap:
  {
    \file_input:n {\l__mermap_definition_id_str.def}
  }


\NewDocumentCommand \mrcapplymap { m }
  {
    \__mermap_create_definition_id:n {#1}
    \__mermap_applymap:
  }


\cs_new_nopar:Npn \__mermap_drawinfo:
  {
    \begin{scope}[every~node/.style={fill=white,fill~opacity=0.8,text~opacity=1,font=\sffamily\footnotesize}]
    \mrcclipmap
    \tl_set:Nn \l__mermap_tile_basename_tl {_dummy_}% not existing file
    \mermapset{map~path={draw=white,double=red}}
    \tikzset{mermap_path_style/.style={draw=white,double=red}}
    \__mermap_drawmap_tiles:
    \node at (mrcmap.center) {
      \begin{tabular}{ll}
      scale      & ca.~\mrcprettymapscale\\
      resolution & ca.~\mrcprettymapresolution\\
      \TeX\nobreakspace tile~size  & ca.~\mrcprettytilesize\\
      width      & ca.~\mrcprettymapwidth\\
      height     & ca.~\mrcprettymapheight\\
      zoom       & $z=\int_use:N \l__mermap_tile_zoom_int$\\
      horizontal & $x\in\{\int_use:N\l__mermap_tile_xmin_int,\ldots,\int_use:N\l__mermap_tile_xmax_int\}$\\
      vertical   & $y\in\{\int_use:N\l__mermap_tile_ymin_int,\ldots,\int_use:N\l__mermap_tile_ymax_int\}$
      \end{tabular}
    };
    \node[above] at (mrcmap.south) {
      \mrcformlat[format~angle=decimal-4]{\mrcmapsouth},
      \SI[round-mode=figures,round-precision=6,detect-all]{\fp_to_decimal:n{
        \c__mermap_scale_radius_fp*(\mrcmapeast-\mrcmapwest)*cosd(\mrcmapsouth)}}{km}
    };
    \node[below] at (mrcmap.north) {
      \mrcformlat[format~angle=decimal-4]{\mrcmapnorth},
      \SI[round-mode=figures,round-precision=6,detect-all]{\fp_to_decimal:n{
        \c__mermap_scale_radius_fp*(\mrcmapeast-\mrcmapwest)*cosd(\mrcmapnorth)}}{km}
    };
    \node[rotate=90] at ([xshift=3mm]mrcmap.west) {
      \mrcformlon[format~angle=decimal-4]{\mrcmapwest},
      \SI[round-mode=figures,round-precision=6,detect-all]{\fp_to_decimal:n{
        \c__mermap_scale_radius_fp*(\mrcmapnorth-\mrcmapsouth)}}{km}
    };
    \node[rotate=90] at ([xshift=-3mm]mrcmap.east) {
      \mrcformlon[format~angle=decimal-4]{\mrcmapeast},
      \SI[round-mode=figures,round-precision=6,detect-all]{\fp_to_decimal:n{
        \c__mermap_scale_radius_fp*(\mrcmapnorth-\mrcmapsouth)}}{km}
    };
    \end{scope}%
  }

\NewDocumentCommand{\mrcdrawinfo}{ }{ \__mermap_drawinfo: }


%---- geodetic network ---------------------------------------------------------


\dim_new:N \l__mermap_network_distance_dim
\int_new:N \l__mermap_network_pieces_int
\tl_new:N  \l__mermap_network_font_tl

\keys_define:nn { mermap }
  {
    network~distance .dim_set:N = \l__mermap_network_distance_dim,
    network~pieces   .int_set:N = \l__mermap_network_pieces_int,
    network~font     .tl_set:N  = \l__mermap_network_font_tl,
  }

\keys_set:nn { mermap }
  {
    network~pieces   = 8,
    network~distance = 2cm,
    network~font     = \fontsize{4pt}{4pt}\sffamily,
  }

\cs_new_nopar:Npn \__mermap_compute_network_step:nn #1#2
  {
    \fp_set:Nn \l__mermap_tmpa_fp
    {
      min ( \l__mermap_network_pieces_int, round((#1)/\l__mermap_network_distance_dim) )
    }
    \fp_set:Nn \l__mermap_tmpb_fp { (#2)/\l__mermap_tmpa_fp }
    \fp_set:Nn \l__mermap_tmpa_fp { floor(ln(\l__mermap_tmpb_fp)/ln(10)) }
    \fp_compare:nNnTF {\l__mermap_tmpa_fp} < {0}
      {
        \fp_compare:nNnTF {\l__mermap_tmpa_fp} > {-5}
          {
            \use:x
            {
              \exp_not:N\keys_set:nn { mermap }{ format~angle=decimal\fp_to_int:N\l__mermap_tmpa_fp}
            }
          }
          {
            \keys_set:nn { mermap }{ format~angle=decimal }
          }
      }
      {
        \keys_set:nn { mermap }{ format~angle=decimal-0 }
      }
    \fp_set:Nn \l__mermap_tmpa_fp { 10^\l__mermap_tmpa_fp }
    \fp_set:Nn \l__mermap_tmpb_fp { \l__mermap_tmpb_fp/\l__mermap_tmpa_fp }
    \fp_compare:nNnTF {abs(\l__mermap_tmpb_fp-1)} < {abs(\l__mermap_tmpb_fp-2)}
      {
        \fp_compare:nNnTF {abs(\l__mermap_tmpb_fp-1)} < {abs(\l__mermap_tmpb_fp-5)}
        {
          \fp_set:Nn \l__mermap_result_fp {\l__mermap_tmpa_fp}
        }
        {
          \fp_set:Nn \l__mermap_result_fp {5*\l__mermap_tmpa_fp}
        }
      }
      {
        \fp_compare:nNnTF {abs(\l__mermap_tmpb_fp-2)} < {abs(\l__mermap_tmpb_fp-5)}
        {
          \fp_set:Nn \l__mermap_result_fp {2*\l__mermap_tmpa_fp}
        }
        {
          \fp_set:Nn \l__mermap_result_fp {5*\l__mermap_tmpa_fp}
        }
      }
  }


\NewDocumentCommand\mrcdrawnetwork { o }
  {
    \begin{scope}[every~node/.style={inner~sep=0.5pt,black!50!gray,
      font=\l__mermap_network_font_tl,fill=white,opacity=0.3,text~opacity=1}]
    \IfNoValueF {#1} { \keys_set:nn { mermap } {#1} }
    \tl_use:N \l__mermap_tikz_map_clip_tl
    \__mermap_compute_network_step:nn {\l__mermap_tex_height_fp}{\l__mermap_mapnorth_fp-\l__mermap_mapsouth_fp}
    \fp_set:Nn \l__mermap_tmpa_fp { ceil(\l__mermap_mapsouth_fp/\l__mermap_result_fp)*\l__mermap_result_fp}
    \fp_compare:nNnT {\l__mermap_tmpa_fp-\l__mermap_mapsouth_fp} < {1e-10}
      {
        \fp_add:Nn \l__mermap_tmpa_fp {\l__mermap_result_fp}
      }
    \fp_while_do:nNnn {\l__mermap_tmpa_fp} < {\l__mermap_mapnorth_fp}
      {
        \tl_set:Nn \l__mermap_tmpa_tl {\fp_use:N\l__mermap_tmpa_fp}
        \draw[gray,very~thin] (mrc~cs\c_colon_str lat=\l__mermap_tmpa_tl,lon=\mrcmapwest)
          coordinate (mermap_temp)
          node[right=1mm,inner~sep=0.5pt,black!50!gray,font=\l__mermap_network_font_tl,
            fill=white,opacity=0.3,text~opacity=1,
            ]{\mrcformlat{\l__mermap_tmpa_tl}}
          -- (mermap_temp -| mrcmap.east)
          node[left=1mm,inner~sep=0.5pt,black!50!gray,font=\l__mermap_network_font_tl,
            fill=white,opacity=0.3,text~opacity=1,
          ]{\mrcformlat{\l__mermap_tmpa_tl}}
          ;
        \fp_add:Nn \l__mermap_tmpa_fp {\l__mermap_result_fp}
      }
    \__mermap_compute_network_step:nn {\l__mermap_tex_width_fp}{\l__mermap_mapeast_fp-\l__mermap_mapwest_fp}
    \fp_set:Nn \l__mermap_tmpa_fp { ceil(\l__mermap_mapwest_fp/\l__mermap_result_fp)*\l__mermap_result_fp}
    \fp_compare:nNnT {\l__mermap_tmpa_fp-\l__mermap_mapwest_fp} < {1e-10}
      {
        \fp_add:Nn \l__mermap_tmpa_fp {\l__mermap_result_fp}
      }
    \fp_while_do:nNnn {\l__mermap_tmpa_fp} < {\l__mermap_mapeast_fp}
      {
        \tl_set:Nn \l__mermap_tmpa_tl {\fp_use:N\l__mermap_tmpa_fp}
        \draw[gray,very~thin] (mrc~cs\c_colon_str lon=\l__mermap_tmpa_tl,lat=\mrcmapsouth)
          coordinate (mermap_temp)
          node[above=1mm,inner~sep=0.5pt,black!50!gray,font=\l__mermap_network_font_tl,
            fill=white,opacity=0.3,text~opacity=1,
            ]{\mrcformlon{\l__mermap_tmpa_tl}}
          -- (mermap_temp |- mrcmap.north)
          node[below=1mm,inner~sep=0.5pt,black!50!gray,font=\l__mermap_network_font_tl,
            fill=white,opacity=0.3,text~opacity=1,
          ]{\mrcformlon{\l__mermap_tmpa_tl}}
          ;
        \fp_add:Nn \l__mermap_tmpa_fp {\l__mermap_result_fp}
      }
    \end{scope}
  }


%---- scaling and formatting ---------------------------------------------------

\tl_new:N \l__mermap_temp_tl

\keys_define:nn { mermap }
  {
    format~south .cs_set:Np = \__mermap_format_south:n #1,
    format~north .cs_set:Np = \__mermap_format_north:n #1,
    format~east .cs_set:Np  = \__mermap_format_east:n #1,
    format~west .cs_set:Np  = \__mermap_format_west:n #1,
    __format_angle .cs_set:Np = \__mermap_format_angle:n #1,
    format~angle .choice:,
    format~angle .value_required:n = true,
    format~angle / decimal   .meta:nn = {mermap}{__format_angle=\ang{##1}},
    format~angle / decimal-0 .meta:nn = {mermap}{__format_angle={\ang[round-mode=places,round-precision=0]{##1}}},
    format~angle / decimal-1 .meta:nn = {mermap}{__format_angle={\ang[round-mode=places,round-precision=1]{##1}}},
    format~angle / decimal-2 .meta:nn = {mermap}{__format_angle={\ang[round-mode=places,round-precision=2]{##1}}},
    format~angle / decimal-3 .meta:nn = {mermap}{__format_angle={\ang[round-mode=places,round-precision=3]{##1}}},
    format~angle / decimal-4 .meta:nn = {mermap}{__format_angle={\ang[round-mode=places,round-precision=4]{##1}}},
    format~angle / degree    .meta:nn = {mermap}{format~angle=decimal-0},
    format~angle / minute    .meta:nn = {mermap}{__format_angle=\__mermap_format_angle_minute:n{##1}},
    format~angle / second    .meta:nn = {mermap}{__format_angle=\__mermap_format_angle_second:n{##1}},
    format~NEWS~absolute .meta:nn      = {mermap}{
      format~south = {##1}, format~north = {##1}, format~east = {##1}, format~west = {##1} },
    format~NEWS~numeric .meta:nn      = {mermap}{
      format~south = {$-$##1}, format~north = {##1}, format~east = {##1}, format~west = {$-$##1} },
  }


\keys_set:nn { mermap }
  {
    format~south = {#1\,S},
    format~north = {#1\,N},
    format~east  = {#1\,E},
    format~west  = {#1\,W},
    format~angle = decimal-4,
  }


\NewExpandableDocumentCommand{\mrckmtotex}{ m }
  {
    \fp_to_dim:n { (#1)/\l__mermap_scale_fp }
  }

\NewExpandableDocumentCommand{\mrcmiletotex}{ m }
  {
    \fp_to_dim:n { (#1)*\c__mermap_mile_fp/\l__mermap_scale_fp }
  }

\NewExpandableDocumentCommand{\mrctextokm}{ m }
  {
    \fp_to_decimal:n { (#1)*\l__mermap_scale_fp }
  }

\NewExpandableDocumentCommand{\mrctextomile}{ m }
  {
    \fp_to_decimal:n { (#1)/\c__mermap_mile_fp*\l__mermap_scale_fp }
  }

\NewDocumentCommand{\mrcprettymapscale}{ }
  {
    1\,\c_colon_str\,\num[round-mode=figures,round-precision=3,detect-all]{\fp_to_decimal:N \l__mermap_scale_denominator_fp}
  }


\cs_new_nopar:Npn \__mermap_pretty_distance:n #1
  {
    \fp_set:Nn \l__mermap_tmpa_fp { #1 }
    \fp_compare:nNnTF \l__mermap_tmpa_fp < 5
      {
        \SI[round-mode=figures,round-precision=3,detect-all]{\fp_to_decimal:n{1000*\l__mermap_tmpa_fp}}{\meter}
      }
      {
        \SI[round-mode=figures,round-precision=3,detect-all]{\fp_to_decimal:N \l__mermap_tmpa_fp}{\kilo\meter}
      }
  }


\cs_new_nopar:Npn \__mermap_pretty_length:n #1
  {
    \fp_set:Nn \l__mermap_tmpa_fp { (#1)*\l__mermap_scale_fp }
    \fp_compare:nNnTF \l__mermap_tmpa_fp < 5
      {
        \SI[round-mode=figures,round-precision=3,detect-all]{\fp_to_decimal:n{1000*\l__mermap_tmpa_fp}}{\meter}
      }
      {
        \SI[round-mode=figures,round-precision=3,detect-all]{\fp_to_decimal:N \l__mermap_tmpa_fp}{\kilo\meter}
      }
  }


\NewDocumentCommand{\mrcprettymapwidth}{ }
  {
    \__mermap_pretty_length:n {\mrctexwidth}
  }

\NewDocumentCommand{\mrcprettymapheight}{ }
  {
    \__mermap_pretty_length:n {\mrctexheight}
  }

\NewDocumentCommand{\mrcprettymapresolution}{ }
  {
    \SI[round-mode=places,round-precision=0,detect-all]{\fp_to_decimal:n{1in*\l__mermap_pixel_width_tl/\l__mermap_tex_width_fp}}{dpi}
  }

\NewDocumentCommand{\mrcprettytilesize}{ }
  {
    \SI[round-mode=places,round-precision=3,detect-all]{\fp_to_decimal:n{\l__mermap_tile_size_dim/1mm}}{\milli\meter}
  }


\cs_new_nopar:Npn \__mermap_format_angle_minute:n #1
  {
    \fp_set:Nn \l__mermap_tmpa_fp {floor(#1)}
    \fp_set:Nn \l__mermap_tmpb_fp {round((#1-\l__mermap_tmpa_fp)*60)}
    \ang[add-arc-degree-zero,add-arc-minute-zero]
      {
        \fp_to_int:N \l__mermap_tmpa_fp ;
        \fp_to_int:N \l__mermap_tmpb_fp ;
      }
  }


\cs_new_nopar:Npn \__mermap_format_angle_second:n #1
  {
    \fp_set:Nn \l__mermap_tmpa_fp {floor(#1)}
    \fp_set:Nn \l__mermap_tmpb_fp {floor((#1-\l__mermap_tmpa_fp)*60)}
    \ang[add-arc-degree-zero,add-arc-minute-zero]
      {
        \fp_to_int:N \l__mermap_tmpa_fp ;
        \fp_to_int:N \l__mermap_tmpb_fp ;
        \fp_to_int:n {round(((#1-\l__mermap_tmpa_fp)*60-\l__mermap_tmpb_fp)*60)}
      }
  }

\NewDocumentCommand{\mrcformlat}{ o m }
  {
    \group_begin:
    \IfNoValueF {#1}
      { \keys_set:nn { mermap } {#1} }
    \fp_set:Nn \l__mermap_tmpa_fp {#2}
    \fp_compare:nNnTF \l__mermap_tmpa_fp < 0
      {
        \tl_set:Nx \l__mermap_temp_tl {\fp_to_decimal:n{-\l__mermap_tmpa_fp}}
        \__mermap_format_south:n {\__mermap_format_angle:n{\l__mermap_temp_tl}}
      }
      {
        \tl_set:Nx \l__mermap_temp_tl {\fp_to_decimal:N \l__mermap_tmpa_fp}
        \__mermap_format_north:n {\__mermap_format_angle:n{\l__mermap_temp_tl}}
      }
    \group_end:
  }

\NewDocumentCommand{\mrcformlon}{ o m }
  {
    \group_begin:
    \IfNoValueF {#1}
      { \keys_set:nn { mermap } {#1} }
    \fp_set:Nn \l__mermap_tmpa_fp {#2-360*floor((#2+180)/360)}
    \fp_compare:nNnTF \l__mermap_tmpa_fp < 0
      {
        \tl_set:Nx \l__mermap_temp_tl {\fp_to_decimal:n{-\l__mermap_tmpa_fp}}
        \__mermap_format_west:n{\__mermap_format_angle:n{\l__mermap_temp_tl}}
      }
      {
        \tl_set:Nx \l__mermap_temp_tl {\fp_to_decimal:N \l__mermap_tmpa_fp}
        \__mermap_format_east:n {\__mermap_format_angle:n{\l__mermap_temp_tl}}
      }
    \group_end:
  }


%---- scale bars ---------------------------------------------------------------

\bool_new:N \l__mermap_scalebar_double_bool
\bool_new:N \l__mermap_scalebar_transparent_bool
\dim_new:N  \l__mermap_scalebar_height_dim
\fp_new:N   \l__mermap_scalebar_width_fp
\int_new:N  \l__mermap_scalebar_partitions_int
\tl_new:N   \l__mermap_scalebar_position_tl


\cs_new_nopar:Npn \__mermap_scalebar_positioning:w #1#2#3#4#5;#6;#7 \q_stop
  {
    \tl_if_empty:nTF {#5}
    {
      \fp_set:Nn \l__mermap_tmpa_fp {0}
      \fp_set:Nn \l__mermap_tmpb_fp {0}
    }
    {
      \fp_set:Nn \l__mermap_tmpa_fp {#3*(#5)}
      \tl_if_empty:nTF {#6}
      {
        \fp_set:Nn \l__mermap_tmpb_fp {#4*(#5)}
      }
      {
        \fp_set:Nn \l__mermap_tmpb_fp {#4*(#6)}
      }
    }
    \tl_set:Nx \l__mermap_scalebar_at_tl
      {
        {([xshift=\fp_to_dim:N\l__mermap_tmpa_fp,yshift=\fp_to_dim:N\l__mermap_tmpb_fp]mrcmap.#1)}
      }
    \tl_set:Nn \l__mermap_scalebar_placement_tl {#2}
  }

\keys_define:nn { mermap/scalebar }
  {
    width-in-km    .fp_set:N   = \l__mermap_scalebar_width_fp,
    width-in-kilometer .meta:nn    = { mermap/scalebar }{ width-in-km={#1} },
    width-in-meter .meta:nn    = { mermap/scalebar }{ width-in-km={(#1)/1000} },
    width-in-mile  .meta:nn    = { mermap/scalebar }{ width-in-km={(#1)*\c__mermap_mile_fp} },
    width-in-yard  .meta:nn    = { mermap/scalebar }{ width-in-km={(#1)*0.0009144} },
    partitions     .int_set:N  = \l__mermap_scalebar_partitions_int,
    height         .dim_set:N  = \l__mermap_scalebar_height_dim,
    at             .tl_set:N   = \l__mermap_scalebar_at_tl,
    placement      .tl_set:N   = \l__mermap_scalebar_placement_tl,
    major~style    .code:n     = {\tikzset{mrcscalebarmajor/.style={#1}}},
    minor~style    .code:n     = {\tikzset{mrcscalebarminor/.style={#1}}},
    double         .bool_set:N         = \l__mermap_scalebar_double_bool,
    single         .bool_set_inverse:N = \l__mermap_scalebar_double_bool,
    transparent    .bool_set:N         = \l__mermap_scalebar_transparent_bool,
    solid          .bool_set_inverse:N = \l__mermap_scalebar_transparent_bool,
    scale          .code:n     = {\fp_set:Nn \l__mermap_scale_fp { #1 / (1cm*100000) }},
    south-east-inside .code:n =
      { \__mermap_scalebar_positioning:w {south~east}{above~left}{-1}{1}#1;;\q_stop },
    south-east-outside .code:n =
      { \__mermap_scalebar_positioning:w {south~east}{below~left}{-1}{-1}#1;;\q_stop },
    south-west-inside .code:n =
      { \__mermap_scalebar_positioning:w {south~west}{above~right}{1}{1}#1;;\q_stop },
    south-west-outside .code:n =
      { \__mermap_scalebar_positioning:w {south~west}{below~right}{1}{-1}#1;;\q_stop },
    north-west-inside .code:n =
      { \__mermap_scalebar_positioning:w {north~west}{below~right}{1}{-1}#1;;\q_stop },
    north-west-outside .code:n =
      { \__mermap_scalebar_positioning:w {north~west}{above~right}{1}{1}#1;;\q_stop },
    north-east-inside .code:n =
      { \__mermap_scalebar_positioning:w {north~east}{below~left}{-1}{-1}#1;;\q_stop },
    north-east-outside .code:n =
      { \__mermap_scalebar_positioning:w {north~east}{above~left}{-1}{1}#1;;\q_stop },
  }

\keys_set:nn { mermap/scalebar }
  {
    width-in-km = 0,
    partitions  = 5,
    double      = true,
    transparent = true,
    height      = 2mm,
    at           = {(0,0)},
    placement    =,
    major~style  =,
    minor~style  =,
  }

\cs_new_nopar:Npn \__mermap_drawscalebar:
  {
    \use:x
    {
      \exp_not:N\node[name=mrcscalebar,
        at={\exp_not:V\l__mermap_scalebar_at_tl},
        \exp_not:V\l__mermap_scalebar_placement_tl,
        line~width=0mm,inner~sep=0mm,outer~sep=0mm,draw=none,fill=none,rectangle,
        minimum~width=\mrckmtotex{\l__mermap_scalebar_width_fp},
        minimum~height=\l__mermap_scalebar_height_dim]{};
    }
    \begin{scope}[shift=(mrcscalebar.south~west)]
    \__mermap_tikz_path_begin:n { fill=black, mrcscalebarmajor }
    \pgfseteorule
    \fp_set:Nn \l__mermap_tmpa_fp {\l__mermap_scalebar_width_fp/\l__mermap_scale_fp} % Breite
    \pgfpathrectangle{\pgfpoint{0pt}{0pt}}
      {\pgfpoint{\fp_to_dim:N\l__mermap_tmpa_fp}{\l__mermap_scalebar_height_dim}}
    \bool_if:NF \l__mermap_scalebar_transparent_bool
      {
        \__mermap_tikz_path_end:
        \__mermap_tikz_path_begin:n { fill=white, mrcscalebarminor }
        \fp_set:Nn \l__mermap_tmpa_fp {\l__mermap_scalebar_width_fp/\l__mermap_scale_fp}
      }
    \fp_set:Nn \l__mermap_tmpb_fp {\l__mermap_tmpa_fp/\l__mermap_scalebar_partitions_int}
    \bool_if:NTF \l__mermap_scalebar_double_bool
    {
      \dim_set:Nn \l__mermap_tmpb_dim {\l__mermap_scalebar_height_dim/2}
      \dim_set:Nn \l__mermap_tmpa_dim {0.2pt-\l__mermap_tmpb_dim}
      \int_compare:nNnTF \l__mermap_scalebar_partitions_int = 1
        {
          \pgfpathrectangle{\pgfpoint{0.2pt}{\l__mermap_tmpb_dim}}
            {\pgfpoint{\fp_to_dim:n{\l__mermap_tmpb_fp-0.4pt}}{\l__mermap_tmpa_dim}}
        }
        {
          \pgfpathrectangle{\pgfpoint{0.2pt}{\l__mermap_tmpb_dim}}
            {\pgfpoint{\fp_to_dim:n{\l__mermap_tmpb_fp-0.2pt}}{\l__mermap_tmpa_dim}}
        }
      \int_step_inline:nn { \l__mermap_scalebar_partitions_int-1 }
        {
          \dim_set:Nn \l__mermap_tmpa_dim {-\l__mermap_tmpa_dim}
          \int_compare:nNnTF {##1+1} = \l__mermap_scalebar_partitions_int
            {
              \pgfpathrectangle{\pgfpoint{\fp_to_dim:n{##1*\l__mermap_tmpb_fp}}{\l__mermap_tmpb_dim}}
                {\pgfpoint{\fp_to_dim:n{\l__mermap_tmpb_fp-0.2pt}}{\l__mermap_tmpa_dim}}
            }
            {
              \pgfpathrectangle{\pgfpoint{\fp_to_dim:n{##1*\l__mermap_tmpb_fp}}{\l__mermap_tmpb_dim}}
                {\pgfpoint{\fp_to_dim:N\l__mermap_tmpb_fp}{\l__mermap_tmpa_dim}}
            }
        }
    }
    {
      \dim_set:Nn \l__mermap_tmpa_dim {\l__mermap_scalebar_height_dim-0.4pt}
      \int_step_inline:nnnn { 1 }{ 2 }{ \l__mermap_scalebar_partitions_int-1 }
        {
          \int_compare:nNnTF {##1+1} = \l__mermap_scalebar_partitions_int
            {
              \pgfpathrectangle{\pgfpoint{\fp_to_dim:n{##1*\l__mermap_tmpb_fp}}{0.2pt}}
                {\pgfpoint{\fp_to_dim:n{\l__mermap_tmpb_fp-0.2pt}}{\l__mermap_tmpa_dim}}
            }
            {
              \pgfpathrectangle{\pgfpoint{\fp_to_dim:n{##1*\l__mermap_tmpb_fp}}{0.2pt}}
                {\pgfpoint{\fp_to_dim:N\l__mermap_tmpb_fp}{\l__mermap_tmpa_dim}}
            }
        }
    }
    \__mermap_tikz_path_end:
    \end{scope}
  }

\msg_new:nnnn{ mercatormap }{ scalebar-too-large }
  { The~width~of~the~scale~bar~is~too~large:~#1. }
  {
    You~should~provide~a~smaller~value~by~using~width-in-km~or~width-in-mile.
  }

\msg_new:nnnn{ mercatormap }{ scalebar-scale-unset }
  { The~map~scale~is~unknown. }
  {
    Use~\token_to_str:N \mrcdrawscalebar \ with~a~defined~map~or~set~'scale'~
    explicitely.
  }

\NewDocumentCommand \mrcdrawscalebar { o }
  {
    \group_begin:
    \IfNoValueF {#1} { \keys_set:nn { mermap/scalebar } {#1} }
    \fp_compare:nNnT \l__mermap_scale_fp = 0
      {
        \msg_error:nn{ mercatormap }{ scalebar-scale-unset }
      }
    \fp_compare:nNnT {\l__mermap_scalebar_width_fp/\l__mermap_scale_fp} > {575cm}
      {
        \msg_error:nnx{ mercatormap }{ scalebar-too-large }
        { \fp_to_dim:n{\l__mermap_scalebar_width_fp/\l__mermap_scale_fp} }
      }
    \__mermap_drawscalebar:
    \group_end:
  }

%---- markers ------------------------------------------------------------------

\bool_new:N \l__mermap_marker_show_bool
\bool_new:N \l__mermap_marker_use_links
\bool_new:N \l__mermap_marker_use_urls

\fp_new:N \l__mermap_marker_angle_fp
\fp_new:N \l__mermap_marker_distance_fp
\fp_new:N \l__mermap_marker_inner_radius_fp
\fp_new:N \l__mermap_marker_latitude_fp
\fp_new:N \l__mermap_marker_longitude_fp
\fp_new:N \l__mermap_marker_radius_fp
\fp_new:N \l__mermap_marker_shift_fp

\tl_new:N \l__mermap_every_marker_first_tl
\tl_new:N \l__mermap_every_marker_last_tl
\tl_new:N \l__mermap_marker_alias_tl
\tl_new:N \l__mermap_marker_category_tl
\tl_new:N \l__mermap_marker_contents_tl
\tl_new:N \l__mermap_marker_font_tl
\tl_new:N \l_mermap_marker_generic_tl
\tl_new:N \l__mermap_marker_link_tl
\tl_new:N \l__mermap_marker_pictocontents_tl
\tl_new:N \l__mermap_marker_type_tl
\tl_new:N \l__mermap_marker_url_tl
\tl_new:N \l_mermap_marker_uuid_tl




\use:x
  {
    \cs_new_nopar:Npn \exp_not:N\__mermap_marker_position:w ##1 \c_colon_str ##2 \exp_not:N \q_stop
  }
  {
    \fp_set:Nn \l__mermap_marker_latitude_fp {#1}
    \fp_set:Nn \l__mermap_marker_longitude_fp {#2}
  }


\keys_define:nn { mermap/marker }
  {
    latitude        .fp_set:N   = \l__mermap_marker_latitude_fp,
    lat             .fp_set:N   = \l__mermap_marker_latitude_fp,
    longitude       .fp_set:N   = \l__mermap_marker_longitude_fp,
    lon             .fp_set:N   = \l__mermap_marker_longitude_fp,
    position        .code:n     = {\__mermap_marker_position:w #1 \q_stop},
    named~position  .meta:nn    = {mermap/marker}{latitude=\mrcNPlat{#1},longitude=\mrcNPlon{#1}},
    use~inside      .choice:    =,
    use~inside      .value_required:n = true,
    use~inside/map  .code:n     = { \cs_set_eq:NN \__mermap_if_marker_inside:nnTF \__mermap_if_in_map:nnTF },
    use~inside/vicinity .code:n = { \cs_set_eq:NN \__mermap_if_marker_inside:nnTF \__mermap_if_in_vicinity:nnTF },
    alias           .tl_set:N   = \l__mermap_marker_alias_tl,
    contents        .tl_set:N   = \l__mermap_marker_contents_tl,
    pictocontents   .tl_set:N   = \l__mermap_marker_pictocontents_tl,
    uuid            .tl_set:N   = \l_mermap_marker_uuid_tl,
    generic         .tl_set:N   = \l_mermap_marker_generic_tl,
    url             .tl_set:N   = \l__mermap_marker_url_tl,
    link            .tl_set:N   = \l__mermap_marker_link_tl,
    category        .tl_set:N   = \l__mermap_marker_category_tl,
    type            .tl_set:N   = \l__mermap_marker_type_tl,
    angle           .fp_set:N   = \l__mermap_marker_angle_fp,
    shift           .fp_set:N   = \l__mermap_marker_shift_fp,
    distance        .fp_set:N   = \l__mermap_marker_distance_fp,
    draw            .code:n     = \colorlet{mrcmarkerdraw}{#1},
    fill            .code:n     = \colorlet{mrcmarkerfill}{#1},
    text            .code:n     = \colorlet{mrcmarkertext}{#1},
    font            .tl_set:N   = \l__mermap_marker_font_tl,
    radius          .fp_set:N   = \l__mermap_marker_radius_fp,
    inner~radius    .fp_set:N   = \l__mermap_marker_inner_radius_fp,
    path~style      .code:n     = {\tikzset{mrcpathstyle/.style={#1}}},
    node~style      .code:n     = {\tikzset{mrcnodestyle/.style={#1}}},
    show           .bool_set:N         = \l__mermap_marker_show_bool,
    hide           .bool_set_inverse:N = \l__mermap_marker_show_bool,
    show~category  .code:n      =
      { \str_if_eq:VnT \l__mermap_marker_category_tl {#1} {\bool_set_true:N \l__mermap_marker_show_bool} },
    show~all~but~category  .code:n =
      { \str_if_eq:VnF \l__mermap_marker_category_tl {#1} {\bool_set_true:N \l__mermap_marker_show_bool} },
    hide~category  .code:n      =
      { \str_if_eq:VnT \l__mermap_marker_category_tl {#1} {\bool_set_false:N \l__mermap_marker_show_bool} },
    hide~all~but~category  .code:n =
      { \str_if_eq:VnF \l__mermap_marker_category_tl {#1} {\bool_set_false:N \l__mermap_marker_show_bool} },
    use~links    .bool_set:N         = \l__mermap_marker_use_links,
    ignore~links .bool_set_inverse:N = \l__mermap_marker_use_links,
    use~urls     .bool_set:N         = \l__mermap_marker_use_urls,
    ignore~urls  .bool_set_inverse:N = \l__mermap_marker_use_urls,
    first~options  .tl_set:N = \l__mermap_every_marker_first_tl,
    last~options   .tl_set:N = \l__mermap_every_marker_last_tl,
    style        .choice:    =,
    style  .value_required:n = true,
  }


\keys_set:nn { mermap/marker }
  {
    latitude   = 12,
    longitude  = 49,
    use~inside = map,
    contents   =,
    alias      = noname,
    pictocontents =,
    angle      = 90,
    shift      = 0pt,
    distance   = 5mm,
    fill       = gray!20,
    draw       = gray,
    text       = black,
    radius     = 3mm,
    inner~radius = 2.25mm,
    path~style =,
    node~style =,
    font       = \sffamily\small,
    type       = classic,
    uuid       =,
    generic    =,
    url        =,
    link       =,
    category   =,
    show       = true,
    use~links  = true,
    use~urls   = true,
  }


\NewExpandableDocumentCommand\mrcmarkerlatitude{}{\fp_to_decimal:N \l__mermap_marker_latitude_fp}
\NewExpandableDocumentCommand\mrcmarkerlongitude{}{\fp_to_decimal:N \l__mermap_marker_longitude_fp}
\NewDocumentCommand\mrcmarkercontents{}{\tl_use:N \l__mermap_marker_contents_tl}
\NewDocumentCommand\mrcmarkerpictocontents{}{\tl_use:N \l__mermap_marker_pictocontents_tl}
\NewExpandableDocumentCommand\mrcmarkeruuid{}{\tl_use:N \l_mermap_marker_uuid_tl}
\NewDocumentCommand\mrcmarkergeneric{}{\tl_use:N \l_mermap_marker_generic_tl}
\NewExpandableDocumentCommand\mrcmarkercategory{}{\tl_use:N \l__mermap_marker_category_tl}
\NewDocumentCommand\mrcmarkerfont{}{\tl_use:N \l__mermap_marker_font_tl}
\NewExpandableDocumentCommand\mrcmarkerangle{}{\fp_to_decimal:N \l__mermap_marker_angle_fp}
\NewExpandableDocumentCommand\mrcmarkershift{}{\fp_to_dim:N \l__mermap_marker_shift_fp}
\NewExpandableDocumentCommand\mrcmarkerdistance{}{\fp_to_dim:N \l__mermap_marker_distance_fp}
\NewExpandableDocumentCommand\mrcmarkerradius{}{\fp_to_dim:N \l__mermap_marker_radius_fp}
\NewExpandableDocumentCommand\mrcmarkerinnerradius{}{\fp_to_dim:N \l__mermap_marker_inner_radius_fp}


\NewDocumentCommand \mrcnewmarkerstyle { m +m }
  {
    \keys_define:nn { mermap/marker/style }
      {
        #1 .meta:nn = {mermap/marker}{#2}
      }
  }


\msg_new:nnnn{ mercatormap }{ markertype-undefined }
  { Marker~type~'#1'~is~unknown. }
  {
    I~guess~'type=#1'~for~setting~a~marker~type~contains~a~spelling~error.
  }


\cs_new_nopar:Npn \__mermap_hyper_path:n #1
  {
    \pgfpointanchor{path~picture~bounding~box}{south~west}
    \pgf@xb-\pgf@x
    \pgf@yb-\pgf@y
    \pgfpointanchor{path~picture~bounding~box}{north~east}
    \advance\pgf@xb\pgf@x
    \advance\pgf@yb\pgf@y
    \advance\pgf@x-1bp
    \advance\pgf@y-1bp
    \advance\pgf@xb-2bp
    \advance\pgf@yb-2bp
    \pgftext[at={\pgfqpoint{\pgf@x}{\pgf@y}},right,top]
    {
      \hypersetup{pdfborder=0~0~0}
      #1{\vrule height\pgf@yb depth0ptwidth0pt\vrule height0ptdepth0ptwidth\pgf@xb}
    }
  }


\cs_new_nopar:Npn \__mermap_hyper_path_insert:
  {
    \cs_if_exist:NT \hypersetup
      {
        \bool_if:NT \l__mermap_marker_use_urls
        {
          \tl_if_empty:NF \l__mermap_marker_url_tl
            {
              \__mermap_hyper_path:n {\href{\l__mermap_marker_url_tl}}
            }
        }
        \bool_if:NT \l__mermap_marker_use_links
        {
          \tl_if_empty:NF \l__mermap_marker_link_tl
            {
              \__mermap_hyper_path:n {\hyperlink{\l__mermap_marker_link_tl}}
            }
        }
      }
  }


\tikzset
  {
    mrchyperpath/.style =
      {
        path~picture = {\__mermap_hyper_path_insert:}
      }
  }

\NewDocumentCommand \mrcmarker { m }
  {
    \group_begin:
    \keys_set:nV { mermap/marker } \l__mermap_every_marker_first_tl
    \keys_set:nn { mermap/marker } { #1 }
    \keys_set:nV { mermap/marker } \l__mermap_every_marker_last_tl
    \__mermap_if_marker_inside:nnTF {\l__mermap_marker_latitude_fp} {\l__mermap_marker_longitude_fp}
    {
      \bool_if:NT \l__mermap_marker_show_bool
      {
        \pgfnodealias{\l__mermap_marker_alias_tl}{mrcpos}
        \begin{scope}[shift=(mrcpos)]
        \cs_if_exist_use:cF{__mermap_drawmarker_\l__mermap_marker_type_tl}
          {
            \msg_error:nnx{ mercatormap }{ markertype-undefined }{ \l__mermap_marker_type_tl }
          }
        \end{scope}
      }
    }
    {}
    \group_end:
  }


\cs_new:Npn \__mermap_new_marker_type:nn #1
  {
    \cs_new:cpn {__mermap_drawmarker_#1}
  }


\NewDocumentCommand \mrcnewmarkertype { m }
  {
    \__mermap_new_marker_type:nn {#1}
  }


\__mermap_new_marker_type:nn {classic}
  {
    \node[circle,fill=black,inner~sep=0pt,minimum~width=4pt,
      pin={[text=mrcmarkertext,font=\mrcmarkerfont,
        pin~distance=\mrcmarkerradius,
        pin~position=\mrcmarkerangle,mrcnodestyle,mrchyperpath]\mrcmarkercontents}] {};
  }

\__mermap_new_marker_type:nn {pin}
  {
    \tl_set:Nx \l__mermap_tmpa_tl {\fp_to_dim:N \l__mermap_marker_distance_fp}
    \path[fill=mrcmarkerfill,draw=none,fill~opacity=0.7]
      (0,0) -- (0.1,\l__mermap_tmpa_tl) -- (-0.1,\l__mermap_tmpa_tl) -- cycle;
    \node[fill=white,draw=none,text=mrcmarkertext,
      above,font=\mrcmarkerfont,inner~sep=0.5mm,align=center,
      line~width=0mm,xshift=\mrcmarkershift,
      fill~opacity=0.7,text~opacity=1,xshift=0mm,mrcnodestyle,mrchyperpath]
      (pin_node) at (0,\l__mermap_tmpa_tl) {\mrcmarkercontents};
    \path[draw=mrcmarkerdraw,fill=none,line~join=round,mrcpathstyle]
      (0,0) -- (0.1,\l__mermap_tmpa_tl) -- (pin_node.south~east) -- (pin_node.north~east)
      -- (pin_node.north~west) -- (pin_node.south~west)
      -- (-0.1,\l__mermap_tmpa_tl) [line~join=bevel] --  cycle;
  }

\__mermap_new_marker_type:nn {pinflip}
  {
    \tl_set:Nx \l__mermap_tmpa_tl {\fp_to_dim:N \l__mermap_marker_distance_fp}
    \path[fill=mrcmarkerfill,draw=none,fill~opacity=0.7]
      (0,0) -- (-0.1,-\l__mermap_tmpa_tl) -- (0.1,-\l__mermap_tmpa_tl) -- cycle;
    \node[fill=white,draw=none,text=mrcmarkertext,
      below,font=\mrcmarkerfont,inner~sep=0.5mm,align=center,
      line~width=0mm,xshift=\mrcmarkershift,
      fill~opacity=0.7,text~opacity=1,xshift=0mm,mrcnodestyle,mrchyperpath]
      (pin_node) at (0,-\l__mermap_tmpa_tl) {\mrcmarkercontents};
    \path[draw=mrcmarkerdraw,fill=none,line~join=round,mrcpathstyle]
      (0,0) -- (-0.1,-\l__mermap_tmpa_tl) -- (pin_node.north~west) -- (pin_node.south~west)
      -- (pin_node.south~east) -- (pin_node.north~east)
      -- (0.1,-\l__mermap_tmpa_tl)  [line~join=bevel] -- cycle;
  }


\cs_new_nopar:Npn \__mermap_tikz_drop_path:n #1
  {
    \tl_set:Nn \l__mermap_tmpa_tl {\fp_to_dim:N\l__mermap_marker_radius_fp}
    \tl_set:Nn \l__mermap_tmpb_tl {\fp_to_dim:n{\l__mermap_marker_radius_fp*0.552}}
    \__mermap_tikz_path_begin:n
    {
      line~join=bevel,draw=mrcmarkerdraw,fill=mrcmarkerfill,mrcpathstyle,mrchyperpath
    }
    \pgfpathmoveto{\pgfpoint{0pt}{\fp_to_dim:n{-2*\l__mermap_marker_radius_fp-\l__mermap_marker_shift_fp}}}
    \pgfpathcurveto{\pgfpoint{\l__mermap_tmpb_tl}{-\l__mermap_tmpa_tl}}{\pgfpoint{\l__mermap_tmpa_tl}{-\l__mermap_tmpb_tl}}
      {\pgfpoint{\l__mermap_tmpa_tl}{0pt}}
    \pgfpathcurveto{\pgfpoint{\l__mermap_tmpa_tl}{\l__mermap_tmpb_tl}}{\pgfpoint{\l__mermap_tmpb_tl}{\l__mermap_tmpa_tl}}
      {\pgfpoint{0pt}{\l__mermap_tmpa_tl}}
    \pgfpathcurveto{\pgfpoint{-\l__mermap_tmpb_tl}{\l__mermap_tmpa_tl}}{\pgfpoint{-\l__mermap_tmpa_tl}{\l__mermap_tmpb_tl}}
      {\pgfpoint{-\l__mermap_tmpa_tl}{0pt}}
    \pgfpathcurveto{\pgfpoint{-\l__mermap_tmpa_tl}{-\l__mermap_tmpb_tl}}{\pgfpoint{-\l__mermap_tmpb_tl}{-\l__mermap_tmpa_tl}}
      {\pgfpoint{0pt}{\fp_to_dim:n{-2*\l__mermap_marker_radius_fp-\l__mermap_marker_shift_fp}}}
    \pgfpathclose
    #1
    \__mermap_tikz_path_end:
  }

\cs_new_nopar:Npn \__mermap_tikz_circle_node:
  {
    \node[circle,inner~sep=0pt,font=\mrcmarkerfont,text=mrcmarkertext,mrcnodestyle]
      {
        \hbox_set:Nn \l__mermap_tmpa_box {\mrcmarkercontents}
        \fp_compare:nNnT {\box_wd:N \l__mermap_tmpa_box} > {1.5*\l__mermap_marker_radius_fp}
        {
          \box_resize_to_wd_and_ht:Nnn \l__mermap_tmpa_box
            {\fp_to_dim:n {1.5*\l__mermap_marker_radius_fp}}
            {\box_ht:N \l__mermap_tmpa_box}
        }
        \box_use_drop:N \l__mermap_tmpa_box
      };
  }

\__mermap_new_marker_type:nn {drop}
  {
    \begin{scope}[yshift=\fp_to_dim:n{2*\l__mermap_marker_radius_fp+\l__mermap_marker_shift_fp}]
    \__mermap_tikz_drop_path:n {}
    \__mermap_tikz_circle_node:
    \end{scope}
  }

\__mermap_new_marker_type:nn {pictodrop}
  {
    \begin{scope}[yshift=\fp_to_dim:n{2*\l__mermap_marker_radius_fp+\l__mermap_marker_shift_fp}]
    \__mermap_tikz_drop_path:n {}
    \tl_use:N \l__mermap_marker_pictocontents_tl
    \end{scope}
  }

\__mermap_new_marker_type:nn {pictodropring}
  {
    \begin{scope}[yshift=\fp_to_dim:n{2*\l__mermap_marker_radius_fp+\l__mermap_marker_shift_fp}]
    \group_begin:
    \pgfseteorule
    \__mermap_tikz_drop_path:n {
        \pgfpathcircle{\pgfpoint{0pt}{0pt}}{\fp_to_dim:N\l__mermap_marker_inner_radius_fp}
      }
    \group_end:
    \tl_use:N \l__mermap_marker_pictocontents_tl
    \end{scope}
  }

\__mermap_new_marker_type:nn {knob}
  {
    \path[draw=mrcmarkerdraw,fill=mrcmarkerfill,mrcpathstyle,mrchyperpath]
      circle (\fp_to_dim:N\l__mermap_marker_radius_fp);
    \__mermap_tikz_circle_node:
  }

\__mermap_new_marker_type:nn {pictoknob}
  {
    \path[draw=mrcmarkerdraw,fill=mrcmarkerfill,mrcpathstyle,mrchyperpath]
      circle (\fp_to_dim:N\l__mermap_marker_radius_fp);
    \tl_use:N \l__mermap_marker_pictocontents_tl
  }

\__mermap_new_marker_type:nn {pictoknobring}
  {
    \path[draw=mrcmarkerdraw,fill=mrcmarkerfill,mrcpathstyle,mrchyperpath,even~odd~rule]
      circle (\fp_to_dim:N\l__mermap_marker_radius_fp)
      circle (\fp_to_dim:N\l__mermap_marker_inner_radius_fp);
    \tl_use:N \l__mermap_marker_pictocontents_tl
  }

\__mermap_new_marker_type:nn {ringx}
  {
    \tl_set:Nn \l__mermap_tmpa_tl {\fp_to_dim:N\l__mermap_marker_radius_fp}
    \path[draw=mrcmarkerdraw,very~thin]
       (45 \c_colon_str \l__mermap_tmpa_tl)--(225\c_colon_str \l__mermap_tmpa_tl)
       (135\c_colon_str \l__mermap_tmpa_tl)--(315\c_colon_str \l__mermap_tmpa_tl);
    \path[draw=mrcmarkerdraw,fill=mrcmarkerfill,mrcpathstyle,mrchyperpath,even~odd~rule]
      circle (\l__mermap_tmpa_tl) circle (\fp_to_dim:N\l__mermap_marker_inner_radius_fp);
  }

\__mermap_new_marker_type:nn {markx}
  {
    \tl_set:Nn \l__mermap_tmpa_tl {\fp_to_dim:N\l__mermap_marker_radius_fp}
    \path[line~join=bevel,draw=mrcmarkerdraw,fill=mrcmarkerfill,mrcpathstyle,mrchyperpath]
       (0,0) -- (35 \c_colon_str \l__mermap_tmpa_tl) -- (55 \c_colon_str \l__mermap_tmpa_tl) -- cycle
       (0,0) -- (125 \c_colon_str \l__mermap_tmpa_tl) -- (145 \c_colon_str \l__mermap_tmpa_tl) -- cycle
       (0,0) -- (215 \c_colon_str \l__mermap_tmpa_tl) -- (235 \c_colon_str \l__mermap_tmpa_tl) -- cycle
       (0,0) -- (305 \c_colon_str \l__mermap_tmpa_tl) -- (325 \c_colon_str \l__mermap_tmpa_tl) -- cycle;
  }


%---- paths and routes ---------------------------------------------------------


\bool_new:N \l__mermap_path_first_point_bool


\keys_define:nn { mermap }
  {
    every~route .code:n = { \tikzset{ mermap_every_route/.style={#1} } }
  }

\keys_set:nn { mermap }
  {
    every~route =,
  }


\cs_new:Npn \__mermap_tikz_path_begin:n #1
  {
    \path[#1] \pgfextra
  }

\cs_new:Npn \__mermap_tikz_path_end:
  {
    \endpgfextra;
  }

\cs_new_nopar:Npn \__mermap_pgf_moveto_point:nn #1#2
  {
    \pgfpathmoveto{\__mermap_pgfpoint:nn {#1}{#2}}
  }

\cs_new_nopar:Npn \__mermap_pgf_lineto_point:nn #1#2
  {
    \pgfpathlineto{\__mermap_pgfpoint:nn {#1}{#2}}
  }

\cs_new_nopar:Npn \__mermap_route_point #1#2
  {
    \bool_if:NTF \l__mermap_path_first_point_bool
    {
      \__mermap_pgf_moveto_point:nn {#1}{#2}
      \bool_set_false:N \l__mermap_path_first_point_bool
    }
    {
      \__mermap_pgf_lineto_point:nn {#1}{#2}
    }
  }

\cs_new_nopar:Npn \__mermap_route_begin:n #1
  {
    \__mermap_tikz_path_begin:n
      {
        draw,mermap_every_route,#1
      }
    \cs_set_eq:NN \mrcpoint \__mermap_route_point
    \bool_set_true:N \l__mermap_path_first_point_bool
  }

\NewDocumentEnvironment {mrcroute} { O{} }
  {
    \__mermap_route_begin:n {#1}
  }
  {
    \__mermap_tikz_path_end:
  }

\NewDocumentEnvironment {mrcroute*} { O{} }
  {
    \__mermap_route_begin:n {#1}
  }
  {
    \pgfpathclose
    \__mermap_tikz_path_end:
  }

\NewDocumentCommand \mrcrouteinput { s O{} m }
  {
    \__mermap_route_begin:n {#2}
    \file_input:n {#3}
    \IfBooleanT {#1}
    {
      \pgfpathclose
    }
    \__mermap_tikz_path_end:
  }


%---- orthodromes and loxodromes -----------------------------------------------


\fp_new:N \l__mermap_a_x_fp
\fp_new:N \l__mermap_a_y_fp
\fp_new:N \l__mermap_a_z_fp
\fp_new:N \l__mermap_b_x_fp
\fp_new:N \l__mermap_b_y_fp
\fp_new:N \l__mermap_b_z_fp
\fp_new:N \l__mermap_alpha_fp
\fp_new:N \l__mermap_delta_lambda_fp
\fp_new:N \l__mermap_delta_phi_fp
\fp_new:N \l__mermap_n_x_fp
\fp_new:N \l__mermap_n_y_fp
\fp_new:N \l__mermap_n_z_fp
\fp_new:N \l__mermap_psi_fp
\fp_new:N \l__mermap_sin_psi_fp
\fp_new:N \l__mermap_t_fp
\fp_new:N \l__mermap_t_psi_fp
\fp_new:N \l__mermap_t_x_fp
\fp_new:N \l__mermap_t_y_fp
\fp_new:N \l__mermap_t_z_fp
\fp_const:Nn \c__mermap_linearization_threshold_fp { 10e-9 }
\bool_new:N \l__mermap_linearization_bool

\int_new:N \l__mermap_samples_int

\keys_define:nn { mermap }
  {
    samples .int_set:N = \l__mermap_samples_int,
  }

\keys_set:nn { mermap }
  {
    samples = 100,
  }

\tikzset{
  mermap~samples/.code={\mermapset{samples=#1}}
}


\cs_new_nopar:Npn \__mermap_sphere_point:nnn #1#2#3  %  {x}{y}{z}
  {
    \fp_set:Nn \l__mermap_cs_lat_fp { asind(#3/sqrt((#1)^2+(#2)^2+(#3)^2)) }
    \fp_set:Nn \l__mermap_cs_lon_fp { sign(#2)*acosd(#1/sqrt((#1)^2+(#2)^2)) }
    \__mermap_pgfpoint:nn {\l__mermap_cs_lat_fp}{\l__mermap_cs_lon_fp}
  }


\cs_new_nopar:Npn \__mermap_unit_sphere_point:nnn #1#2#3  %  {x}{y}{z} radius 1
  {
    \fp_set:Nn \l__mermap_cs_lat_fp { asind(#3) }
    \fp_set:Nn \l__mermap_cs_lon_fp { sign(#2)*acosd(#1/sqrt((#1)^2+(#2)^2)) }
    \__mermap_pgfpoint:nn {\l__mermap_cs_lat_fp}{\l__mermap_cs_lon_fp}
  }


\cs_new_protected:Npn \__mermap_draw_orthodrome:nnnnn #1#2#3#4#5
  {
    \__mermap_tikz_path_begin:n { draw,mermap_every_route,#1 }
    \__mermap_setup_orthodrome:nnnn { #2 }{ #3 }{ #4 }{ #5 }
    \__mermap_pgf_moveto_point:nn { #2 }{ #3 }
    \int_step_inline:nn { \l__mermap_samples_int }
      {
        \__mermap_point_on_orthodrome:n { ##1/\l__mermap_samples_int }
        \__mermap_pgf_lineto_point:nn{ \l__mermap_cs_lat_fp }{ \l__mermap_cs_lon_fp }
      }
    \__mermap_tikz_path_end:
  }


\cs_new_protected:Npn \__mermap_setup_orthodrome:nnnn #1#2#3#4
  {
    \fp_set:Nn \l__mermap_a_x_fp { cosd(#2)*cosd(#1) }
    \fp_set:Nn \l__mermap_a_y_fp { sind(#2)*cosd(#1) }
    \fp_set:Nn \l__mermap_a_z_fp { sind(#1) }

    \fp_set:Nn \l__mermap_b_x_fp { cosd(#4)*cosd(#3) }
    \fp_set:Nn \l__mermap_b_y_fp { sind(#4)*cosd(#3) }
    \fp_set:Nn \l__mermap_b_z_fp { sind(#3) }

    \fp_set:Nn \l__mermap_psi_fp { acosd( sind(#1)*sind(#3) + cosd(#1)*cosd(#3)*cosd(#4-(#2)) ) }
    \fp_set:Nn \l__mermap_sin_psi_fp { sind(\l__mermap_psi_fp) }

    \bool_set:Nn \l__mermap_linearization_bool { \fp_compare_p:nNn \l__mermap_psi_fp < \c__mermap_linearization_threshold_fp }
  }


\cs_new_protected:Npn \__mermap_point_on_orthodrome:n #1
  {
    \fp_set:Nn \l__mermap_t_fp { #1 }

    \bool_if:NTF \l__mermap_linearization_bool
      {
        \fp_set:Nn \l__mermap_tmpa_fp { 1 - \l__mermap_t_fp }
        \fp_set_eq:NN \l__mermap_tmpb_fp \l__mermap_t_fp
      }
      {
        \fp_set:Nn \l__mermap_t_psi_fp { \l__mermap_t_fp * \l__mermap_psi_fp }
        \fp_set:Nn \l__mermap_tmpa_fp { sind( \l__mermap_psi_fp - \l__mermap_t_psi_fp ) / \l__mermap_sin_psi_fp }
        \fp_set:Nn \l__mermap_tmpb_fp { sind( \l__mermap_t_psi_fp ) / \l__mermap_sin_psi_fp }
      }

    \fp_set:Nn \l__mermap_t_x_fp { \l__mermap_tmpa_fp*\l__mermap_a_x_fp + \l__mermap_tmpb_fp*\l__mermap_b_x_fp }
    \fp_set:Nn \l__mermap_t_y_fp { \l__mermap_tmpa_fp*\l__mermap_a_y_fp + \l__mermap_tmpb_fp*\l__mermap_b_y_fp }
    \fp_set:Nn \l__mermap_t_z_fp { \l__mermap_tmpa_fp*\l__mermap_a_z_fp + \l__mermap_tmpb_fp*\l__mermap_b_z_fp }

    \fp_set:Nn \l__mermap_cs_lat_fp { asind(\l__mermap_t_z_fp) }
    \fp_set:Nn \l__mermap_cs_lon_fp { sign(\l__mermap_t_y_fp)*acosd(\l__mermap_t_x_fp/sqrt(\l__mermap_t_x_fp^2+\l__mermap_t_y_fp^2)) }
  }


\cs_new_protected:Npn \__mermap_angle_at_orthodrome:
  {
    \bool_if:NTF \l__mermap_linearization_bool
    {
      \fp_set:Nn \l__mermap_alpha_fp { 90 }
    }
    {
      \fp_set:Nn \l__mermap_tmpa_fp { cosd( \l__mermap_psi_fp - \l__mermap_t_psi_fp ) }
      \fp_set:Nn \l__mermap_tmpb_fp { cosd( \l__mermap_t_psi_fp ) }
      \fp_set:Nn \l__mermap_n_x_fp { \l__mermap_tmpb_fp*\l__mermap_b_x_fp - \l__mermap_tmpa_fp*\l__mermap_a_x_fp }
      \fp_set:Nn \l__mermap_n_y_fp { \l__mermap_tmpb_fp*\l__mermap_b_y_fp - \l__mermap_tmpa_fp*\l__mermap_a_y_fp }
      \fp_set:Nn \l__mermap_n_z_fp { \l__mermap_tmpb_fp*\l__mermap_b_z_fp - \l__mermap_tmpa_fp*\l__mermap_a_z_fp }
      \fp_set:Nn \l__mermap_tmpa_fp { sqrt( \l__mermap_n_x_fp^2 + \l__mermap_n_y_fp^2 + \l__mermap_n_z_fp^2 ) }
      \fp_set:Nn \l__mermap_n_x_fp { \l__mermap_n_x_fp / \l__mermap_tmpa_fp }
      \fp_set:Nn \l__mermap_n_y_fp { \l__mermap_n_y_fp / \l__mermap_tmpa_fp }
      \fp_set:Nn \l__mermap_n_z_fp { \l__mermap_n_z_fp / \l__mermap_tmpa_fp }
      \fp_set:Nn \l__mermap_alpha_fp { acosd( \l__mermap_n_y_fp*cosd(\l__mermap_cs_lon_fp) - \l__mermap_n_x_fp*sind(\l__mermap_cs_lon_fp) ) }
      \fp_compare:nNnT \l__mermap_n_z_fp < 0
        {
          \fp_set:Nn \l__mermap_alpha_fp { 360 - \l__mermap_alpha_fp }
        }
    }
  }


\NewDocumentCommand \mrcdraworthodrome { O{} mmmm }
  {
    \__mermap_draw_orthodrome:nnnnn {#1}{#2}{#3}{#4}{#5}
  }


\NewDocumentCommand \mrcNPdraworthodrome { O{} mm }
  {
    \__mermap_draw_orthodrome:nnnnn {#1}{\mrcNPlat{#2}}{\mrcNPlon{#2}}{\mrcNPlat{#3}}{\mrcNPlon{#3}}
  }


\cs_new_nopar:Npn \__mermap_ortho_distance:nnnn #1#2#3#4
  {
    \fp_set:Nn \l__mermap_result_fp
    {
      \c__mermap_scale_radius_fp *
      acosd( sind(#1)*sind(#3) + cosd(#1)*cosd(#3)*cosd(#4-(#2)) )
    }
  }


\NewDocumentCommand \mrcstoreorthodistance { mmmmm }
  {
    \__mermap_ortho_distance:nnnn {#2}{#3}{#4}{#5}
    \cs_set_nopar:Npx #1 { \fp_to_decimal:N \l__mermap_result_fp }
  }


\NewDocumentCommand \mrcprettyorthodistance { mmmm }
  {
    \__mermap_ortho_distance:nnnn {#1}{#2}{#3}{#4}
    \__mermap_pretty_distance:n { \l__mermap_result_fp }
  }

\NewDocumentCommand \mrcNPprettyorthodistance { mm }
  {
    \__mermap_ortho_distance:nnnn {\mrcNPlat{#1}}{\mrcNPlon{#1}}{\mrcNPlat{#2}}{\mrcNPlon{#2}}
    \__mermap_pretty_distance:n { \l__mermap_result_fp }
  }


\cs_new_nopar:Npn \__mermap_loxo_distance:nnnn #1#2#3#4
  {
    \fp_set:Nn \l__mermap_delta_phi_fp {(#3-(#1))/180*pi}
    \fp_set:Nn \l__mermap_delta_lambda_fp {(#4-(#2))/180*pi}
    \fp_compare:nNnTF {abs(\l__mermap_delta_phi_fp)} < {1e-5}
      {
        \fp_set:Nn \l__mermap_tmpa_fp { tand(#1) }
        \fp_set:Nn \l__mermap_tmpb_fp { \l__mermap_delta_lambda_fp*cosd(#1)
          /( 1 + (\l__mermap_tmpa_fp + (1+2*\l__mermap_tmpa_fp*\l__mermap_tmpa_fp)*\l__mermap_delta_phi_fp/3)*\l__mermap_delta_phi_fp/2 ) }
        \fp_set:Nn \l__mermap_result_fp {
          sqrt( \l__mermap_delta_phi_fp*\l__mermap_delta_phi_fp + \l__mermap_tmpb_fp*\l__mermap_tmpb_fp ) }
      }
      {
        \fp_set:Nn \l__mermap_result_fp { abs(\l__mermap_delta_phi_fp)
          *sqrt( 1+ (\l__mermap_delta_lambda_fp/( ln(tand(#3/2+45)) - ln(tand(#1/2+45)) ) )^2 ) }
      }
    \fp_set:Nn \l__mermap_result_fp { \c__mermap_scale_radius_fp*180/pi * \l__mermap_result_fp }
  }


\NewDocumentCommand \mrcstoreloxodistance { mmmmm }
  {
    \__mermap_loxo_distance:nnnn {#2}{#3}{#4}{#5}
    \cs_set_nopar:Npx #1 { \fp_to_decimal:N \l__mermap_result_fp }
  }


\NewDocumentCommand \mrcprettyloxodistance { mmmm }
  {
    \__mermap_loxo_distance:nnnn {#1}{#2}{#3}{#4}
    \__mermap_pretty_distance:n { \l__mermap_result_fp }
  }


\NewDocumentCommand \mrcNPprettyloxodistance { mm }
  {
    \__mermap_loxo_distance:nnnn { \mrcNPlat{#1} }{ \mrcNPlon{#1} }{ \mrcNPlat{#2} }{ \mrcNPlon{#2} }
    \__mermap_pretty_distance:n { \l__mermap_result_fp }
  }


\cs_new_protected:Npn \__mermap_orthodrome_point:nnn #1#2#3
  {
    \__mermap_point_on_orthodrome:n { #3 }
    \__mermap_set_named_position { #1 }{ \l__mermap_cs_lat_fp }{ \l__mermap_cs_lon_fp }
    \IfNoValueF { #2 }
      {
        \__mermap_angle_at_orthodrome:
        \cs_set:Npe #2 { \fp_to_decimal:N \l__mermap_alpha_fp }
      }
  }

\NewDocumentCommand \mrcNPfromOrthoFraction { mo mm mm m }
  {
    \__mermap_setup_orthodrome:nnnn { #3 }{ #4 }{ #5 }{ #6 }
    \__mermap_orthodrome_point:nnn { #1 }{ #2 }{ #7 }
  }

\NewDocumentCommand \mrcNPfromOrthoFractionNamed { mo m m m }
  {
    \__mermap_setup_orthodrome:nnnn { \mrcNPlat{#3} }{ \mrcNPlon{#3} }{ \mrcNPlat{#4} }{ \mrcNPlon{#4} }
    \__mermap_orthodrome_point:nnn { #1 }{ #2 }{ #5 }
  }

\NewDocumentCommand \mrcNPfromOrthoDistance { mo mm mm m }
  {
    \__mermap_ortho_distance:nnnn { #3 }{ #4 }{ #5 }{ #6 }
    \fp_compare:nNnTF \l__mermap_result_fp > { 0.001 }
      {
        \__mermap_setup_orthodrome:nnnn { #3 }{ #4 }{ #5 }{ #6 }
        \__mermap_orthodrome_point:nnn { #1 }{ #2 }{ #7 / \l__mermap_result_fp }
      }
      {
        \__mermap_set_named_position { #1 }{ #3 }{ #4 }
        \IfNoValueF { #2 }
          {
            \cs_set:Npn #2 { 90 }
          }
      }
  }

\NewDocumentCommand \mrcNPfromOrthoDistanceNamed { mo m m m }
  {
    \__mermap_ortho_distance:nnnn { \mrcNPlat{#3} }{ \mrcNPlon{#3} }{ \mrcNPlat{#4} }{ \mrcNPlon{#4} }
    \fp_compare:nNnTF \l__mermap_result_fp > { 0.001 }
      {
        \__mermap_setup_orthodrome:nnnn { \mrcNPlat{#3} }{ \mrcNPlon{#3} }{ \mrcNPlat{#4} }{ \mrcNPlon{#4} }
        \__mermap_orthodrome_point:nnn { #1 }{ #2 }{ #5 / \l__mermap_result_fp }
      }
      {
        \__mermap_set_named_position { #1 }{ \mrcNPlat{#3} }{ \mrcNPlon{#3} }
        \IfNoValueF { #2 }
          {
            \cs_set:Npn #2 { 90 }
          }
      }
  }


%---- animations ---------------------------------------------------------------

\bool_new:N \l__mermap_anim_drop_first_frame_bool
\bool_new:N \l__mermap_anim_drop_last_frame_bool

\fp_new:N \l__mermap_anim_a_lat_fp
\fp_new:N \l__mermap_anim_a_lon_fp
\fp_new:N \l__mermap_anim_a_scaledenom_fp
\fp_new:N \l__mermap_anim_a_time_fp
\fp_new:N \l__mermap_anim_b_lat_fp
\fp_new:N \l__mermap_anim_b_lon_fp
\fp_new:N \l__mermap_anim_b_scaledenom_fp
\fp_new:N \l__mermap_anim_b_time_fp
\fp_new:N \l_mermap_anim_angle_fp
\fp_new:N \l_mermap_anim_lat_fp
\fp_new:N \l_mermap_anim_lon_fp
\fp_new:N \l_mermap_anim_scaledenom_fp
\fp_new:N \l_mermap_anim_time_fp

\int_new:N \l__mermap_anim_final_frame_int
\int_new:N \l__mermap_anim_frames_int
\int_new:N \l__mermap_anim_start_frame_int
\int_new:N \l_mermap_anim_frame_int

\seq_new:N \l__mermap_anim_scaledenom_seq

\tl_new:N \l__mermap_anim_timescale_tl
\tl_new:N \l__mermap_anim_timewarp_tl


\NewExpandableDocumentCommand \mrcTimewarpIdentity { m }
  {
    #1
  }

\NewExpandableDocumentCommand \mrcTimewarpSlowStart { m m }
  {
    (#2)^(#1)
  }

\NewExpandableDocumentCommand \mrcTimewarpSlowFinal { m m }
  {
    1 - (1-#2)^(#1)
  }

\NewExpandableDocumentCommand \mrcTimewarpSlowStartFinal { m m }
  {
    %1 - (1-#2)^(#1)
    #2 <= 0.5
    ? (2*(#2))^(#1) / 2
    : 1 - (2-2*(#2))^(#1) / 2
  }


\NewDocumentEnvironment { mrcAnimation }{ m +b }
  {
    \keys_set:nn { mermap/anim }{ #1 }

    \__mermap_anim_autocorrect_scaledenom_seq:
    \int_compare:nNnT \l__mermap_anim_frames_int < 2
      {
        \int_set:Nn \l__mermap_anim_frames_int { 2 }
      }
    \bool_if:NTF \l__mermap_anim_drop_first_frame_bool
      {
        \int_set:Nn \l__mermap_anim_start_frame_int { 2 }
      }
      {
        \int_set:Nn \l__mermap_anim_start_frame_int { 1 }
      }
    \bool_if:NTF \l__mermap_anim_drop_last_frame_bool
      {
        \int_set:Nn \l__mermap_anim_final_frame_int { \l__mermap_anim_frames_int-1 }
      }
      {
        \int_set:Nn \l__mermap_anim_final_frame_int { \l__mermap_anim_frames_int }
      }

    \__mermap_setup_orthodrome:nnnn { \l__mermap_anim_a_lat_fp }{ \l__mermap_anim_a_lon_fp }
                                    { \l__mermap_anim_b_lat_fp }{ \l__mermap_anim_b_lon_fp }

    \__mermap_anim_pop_time_scale:NN \l__mermap_anim_a_time_fp \l__mermap_anim_a_scaledenom_fp
    \__mermap_anim_pop_time_scale:NN \l__mermap_anim_b_time_fp \l__mermap_anim_b_scaledenom_fp

    \int_step_variable:nnNn { \l__mermap_anim_start_frame_int }{ \l__mermap_anim_final_frame_int } \l_mermap_anim_frame_int
      {
        \fp_set:Nn \l_mermap_anim_time_fp { (\l_mermap_anim_frame_int-1)/(\l__mermap_anim_frames_int-1) }
        \fp_set:Nn \l_mermap_anim_time_fp { \l__mermap_anim_timewarp_tl { \l_mermap_anim_time_fp } }

        \__mermap_point_on_orthodrome:n { \l_mermap_anim_time_fp }
        \fp_set_eq:NN \l_mermap_anim_lat_fp \l__mermap_cs_lat_fp
        \fp_set_eq:NN \l_mermap_anim_lon_fp \l__mermap_cs_lon_fp
        \__mermap_set_named_position{ AnimNP }{ \l_mermap_anim_lat_fp }{ \l_mermap_anim_lon_fp }

        \__mermap_angle_at_orthodrome:
        \fp_set_eq:NN \l_mermap_anim_angle_fp \l__mermap_alpha_fp

        \fp_while_do:nNnn \l_mermap_anim_time_fp > \l__mermap_anim_b_time_fp
          {
            \fp_set_eq:NN \l__mermap_anim_a_time_fp \l__mermap_anim_b_time_fp
            \fp_set_eq:NN \l__mermap_anim_a_scaledenom_fp \l__mermap_anim_b_scaledenom_fp
            \__mermap_anim_pop_time_scale:NN \l__mermap_anim_b_time_fp \l__mermap_anim_b_scaledenom_fp
          }
        \fp_set:Nn \l_mermap_anim_scaledenom_fp
          {
            round ( exp (
                ln(\l__mermap_anim_a_scaledenom_fp) +
                ( ln(\l__mermap_anim_b_scaledenom_fp)-ln(\l__mermap_anim_a_scaledenom_fp) ) *
                ( \l_mermap_anim_time_fp-\l__mermap_anim_a_time_fp ) / ( \l__mermap_anim_b_time_fp-\l__mermap_anim_a_time_fp )
              ) )
          }

        #2
      }
  }{}


\cs_new_protected:Npn \__mermap_anim_autocorrect_scaledenom_seq:
  {
    \seq_get_left:NN \l__mermap_anim_scaledenom_seq \l__mermap_anim_timescale_tl
    \bool_lazy_any:nTF
      {
        { \seq_if_empty_p:N \l__mermap_anim_scaledenom_seq }
        { \tl_if_empty_p:N \l__mermap_anim_timescale_tl }
        { \quark_if_no_value_p:N \l__mermap_anim_timescale_tl }
      }
      {
        \seq_set_split:Nnn \l__mermap_anim_scaledenom_seq { - }{ 0/25000 - 1/25000 },
      }
      {
        \fp_compare:nNnF { \__mermap_anim_use_time:o \l__mermap_anim_timescale_tl } = 0
           {
             \seq_put_left:Ne \l__mermap_anim_scaledenom_seq { 0 / \__mermap_anim_use_scale:o \l__mermap_anim_timescale_tl }
           }
      }
    \seq_get_right:NNF \l__mermap_anim_scaledenom_seq \l__mermap_anim_timescale_tl
      {
        \msg_error:nn{ mercatormap }{ anim-scaledenom-invalid }
      }
    \fp_compare:nNnF { \__mermap_anim_use_time:o \l__mermap_anim_timescale_tl } = 1
       {
         \seq_put_right:Ne \l__mermap_anim_scaledenom_seq { 1 / \__mermap_anim_use_scale:o \l__mermap_anim_timescale_tl }
       }
    \fp_set:Nn \l__mermap_anim_a_time_fp { -1 }
    \seq_map_inline:Nn \l__mermap_anim_scaledenom_seq
      {
        \fp_set:Nn \l__mermap_anim_b_time_fp { \__mermap_anim_use_time:n { ##1 } }
        \fp_compare:nNnTF \l__mermap_anim_a_time_fp < \l__mermap_anim_b_time_fp
          {
            \fp_set_eq:NN \l__mermap_anim_a_time_fp \l__mermap_anim_b_time_fp
          }
          {
            \msg_error:nn{ mercatormap }{ anim-scaledenom-invalid }
          }
      }
  }

\cs_new_protected:Npn \__mermap_anim_pop_time_scale:NN #1#2
  {
    \seq_pop_left:NN \l__mermap_anim_scaledenom_seq \l__mermap_anim_timescale_tl
    \fp_set:Nn #1 { \__mermap_anim_use_time:o \l__mermap_anim_timescale_tl }
    \fp_set:Nn #2 { \__mermap_anim_use_scale:o \l__mermap_anim_timescale_tl }
  }

\msg_new:nnnn{ mercatormap }{ anim-scaledenom-invalid }
  { The~animation~scale~denominator~sequence~is~invalid. }
  {
    Check~\seq_use:Nn \l__mermap_anim_scaledenom_seq { ~-~ }~with~the~documentation.~
    Time~values~are~not~strictly~monotonically~increasing.
  }

\cs_new_protected_nopar:Npn \__mermap_anim_set_position:w #1 #2 / #3 \q_stop
  {
    \fp_set:cn { l__mermap_anim_#1_lat_fp }{ #2 }
    \fp_set:cn { l__mermap_anim_#1_lon_fp }{ #3 }
  }

\cs_new_nopar:Npn \__mermap_anim_use_time:w #1 / #2 \q_stop
  {
    #1
  }
\cs_new_nopar:Npn \__mermap_anim_use_time:n #1
  {
    \__mermap_anim_use_time:w #1 \q_stop
  }
\cs_generate_variant:Nn \__mermap_anim_use_time:n { o }

\cs_new_nopar:Npn \__mermap_anim_use_scale:w #1 / #2 \q_stop
  {
    #2
  }
\cs_new_nopar:Npn \__mermap_anim_use_scale:n #1
  {
    \__mermap_anim_use_scale:w #1 \q_stop
  }
\cs_generate_variant:Nn \__mermap_anim_use_scale:n { o }

\keys_define:nn { mermap/anim }
  {
    start-position .code:n = \__mermap_anim_set_position:w { a } #1 \q_stop,
    final-position .code:n = \__mermap_anim_set_position:w { b } #1 \q_stop,
    position       .meta:n = { start-position = #1, final-position = #1 },
    named-start-position .code:n =
      {
        \fp_set:Nn \l__mermap_anim_a_lat_fp { \mrcNPlat{ #1 } }
        \fp_set:Nn \l__mermap_anim_a_lon_fp { \mrcNPlon{ #1 } }
      },
    named-final-position .code:n =
      {
        \fp_set:Nn \l__mermap_anim_b_lat_fp { \mrcNPlat{ #1 } }
        \fp_set:Nn \l__mermap_anim_b_lon_fp { \mrcNPlon{ #1 } }
      },
    named-position     .meta:n     = { named-start-position = #1, named-final-position = #1 },
    frames             .int_set:N  = \l__mermap_anim_frames_int,
    drop-first-frame   .bool_set:N = \l__mermap_anim_drop_first_frame_bool,
    drop-last-frame    .bool_set:N = \l__mermap_anim_drop_last_frame_bool,
    drop-no-frame      .meta:n     = { drop-first-frame=false, drop-last-frame=false },
    scale-denominators .code:n     = \seq_set_split:Nnn \l__mermap_anim_scaledenom_seq { - }{ #1 },
    common-scale-denominator .meta:n = { scale-denominators = 0/#1 - 1/#1 },
    timewarp           .tl_set:N   = \l__mermap_anim_timewarp_tl,
    timewarp-identity         .meta:n = { timewarp = \mrcTimewarpIdentity },
    timewarp-slow-start       .meta:n = { timewarp = \mrcTimewarpSlowStart{#1} },
    timewarp-slow-start       .default:n = 2,
    timewarp-slow-final       .meta:n = { timewarp = \mrcTimewarpSlowFinal{#1} },
    timewarp-slow-final       .default:n = 2,
    timewarp-slow-start-final .meta:n = { timewarp = \mrcTimewarpSlowStartFinal{#1} },
    timewarp-slow-start-final .default:n = 2,
  }

\keys_set:nn { mermap/anim }
  {
    position = 51.4779 / 0,
    frames   = 20,
    drop-no-frame,
    common-scale-denominator = 25000,
    timewarp-identity,
  }

\NewExpandableDocumentCommand\mrcAnimFrame{}{\int_to_arabic:n \l_mermap_anim_frame_int}
\NewExpandableDocumentCommand\mrcAnimTime{}{\fp_to_decimal:N \l_mermap_anim_time_fp}
\NewExpandableDocumentCommand\mrcAnimScaleDenom{}{\fp_to_decimal:N \l_mermap_anim_scaledenom_fp}
\NewExpandableDocumentCommand\mrcAnimLatitude{}{\fp_to_decimal:N \l_mermap_anim_lat_fp}
\NewExpandableDocumentCommand\mrcAnimLongitude{}{\fp_to_decimal:N \l_mermap_anim_lon_fp}
\NewExpandableDocumentCommand\mrcAnimAngle{}{\fp_to_decimal:N \l_mermap_anim_angle_fp}


%---- supplier -----------------------------------------------------------------

\file_input:n { \mrcpkgprefix mercatorsupplier.def }
