summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/latex/mercatormap
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2020-04-20 21:10:20 +0000
committerKarl Berry <karl@freefriends.org>2020-04-20 21:10:20 +0000
commit36db81e567665da0b8e92831b69d2a71971312f3 (patch)
treec543aa6948c99b1ecb316c4386ee34dfeed4d384 /Master/texmf-dist/tex/latex/mercatormap
parentc01e3cc67bce910fad535c50c41da044fc23e882 (diff)
mercatormap (20apr20)
git-svn-id: svn://tug.org/texlive/trunk@54812 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/latex/mercatormap')
-rw-r--r--Master/texmf-dist/tex/latex/mercatormap/mercatormap.sty2294
-rw-r--r--Master/texmf-dist/tex/latex/mercatormap/mercatorpy.def535
-rw-r--r--Master/texmf-dist/tex/latex/mercatormap/mercatorsupplier.def290
3 files changed, 3119 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/latex/mercatormap/mercatormap.sty b/Master/texmf-dist/tex/latex/mercatormap/mercatormap.sty
new file mode 100644
index 00000000000..d05872b77fe
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/mercatormap/mercatormap.sty
@@ -0,0 +1,2294 @@
+%% The LaTeX package mercatormap - version 1.00 (2020/04/20)
+%% mercatormap.sty: geographic coordinates (Mercator projection) and map tiles for TikZ pictures
+%%
+%% -------------------------------------------------------------------------------------------
+%% Copyright (c) 2020 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
+%%
+\RequirePackage{expl3}[2020/02/25]
+\RequirePackage{xparse}
+\ProvidesExplPackage{mercatormap}{2020/04/20}{1.00}
+ {A Web Mercator projection package with map tile support}
+\@ifpackagelater { expl3 } { 2020/02/25 }
+ { }
+ {
+ \PackageError { mercatormap } { Support~package~expl3~too~old }
+ {
+ You~need~to~update~your~installation~of~the~bundles~'l3kernel'~and~
+ 'l3packages'.\MessageBreak
+ Loading~mercatormap~will~abort!
+ }
+ \tex_endinput:D
+ }
+
+\RequirePackage{siunitx}
+\RequirePackage{graphicx,tikz,pdftexcmds}
+
+\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} }
+
+
+%---- 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_tmpa_fp { #1-\l__mermap_mapwest_fp }
+ \fp_sub:Nn \l_tmpa_fp { 360*floor(\l_tmpa_fp/360) }
+ \fp_set:Nn \l_tmpa_fp
+ { \l_tmpa_fp>\l__mermap_westeast_fp
+ ?(\l_tmpa_fp-\l__mermap_westeast_fp>360-\l_tmpa_fp
+ ?\l_tmpa_fp-360
+ :\l_tmpa_fp)
+ :\l_tmpa_fp
+ }
+ \fp_set:Nn \l__mermap_cs_x_fp { \l_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, 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_tmpa_fp { #2-\l__mermap_mapwest_fp }
+ \fp_sub:Nn \l_tmpa_fp { 360*floor(\l_tmpa_fp/360) }
+ \fp_compare:nNnTF \l_tmpa_fp > \l__mermap_westeast_fp
+ {
+ \prg_return_false:
+ }
+ {
+ \fp_set:Nn \l__mermap_cs_x_fp { \l_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, 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_tmpa_fp { #2-\l__mermap_vic_west_fp }
+ \fp_sub:Nn \l_tmpa_fp { 360*floor(\l_tmpa_fp/360) }
+ \fp_compare:nNnTF \l_tmpa_fp > \l__mermap_vic_westeast_fp
+ {
+ \prg_return_false:
+ }
+ {
+ \fp_set:Nn \l__mermap_cs_x_fp { \l_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}
+ {
+ \msg_error:nnx{ mercatormap }{ np-undefined }{ #1 }
+ }
+ }
+
+
+\NewExpandableDocumentCommand \mrcNPlon { m }
+ {
+ \cs_if_exist_use:cF{__mermap__lon__#1}
+ {
+ \msg_error:nnx{ mercatormap }{ np-undefined }{ #1 }
+ }
+ }
+
+
+\NewExpandableDocumentCommand \mrcNPcs { m }
+ {
+ __mrc~cs \c_colon_str {{\mrcNPlat{#1}}{\mrcNPlon{#1}}}
+ }
+
+
+\NewDocumentCommand{\ifmrcNPinmap}{ m }
+ {
+ \__mermap_if_in_map:nnTF{\mrcNPlat{#1}}{\mrcNPlon{#1}}
+ }
+
+
+\NewDocumentCommand{\ifmrcNPinvicinity}{ m }
+ {
+ \__mermap_if_in_vicinity:nnTF{\mrcNPlat{#1}}{\mrcNPlon{#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\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\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\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
+
+\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: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_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_tmpa_tl
+ {
+ \msg_error:nnx{ mercatormap }{ api-key-undefined }{ #2 }
+ }
+ \str_put_right:NV \l__mermap_supply_url_str \l_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_tmpa_fp { \mrcNPlat{##1} }
+ \fp_compare:nNnT \l_tmpa_fp < \l__mermap_supply_south_fp
+ { \fp_set_eq:NN \l__mermap_supply_south_fp \l_tmpa_fp }
+ \fp_compare:nNnT \l_tmpa_fp > \l__mermap_supply_north_fp
+ { \fp_set_eq:NN \l__mermap_supply_north_fp \l_tmpa_fp }
+ \fp_set:Nn \l_tmpa_fp { \mrcNPlon{##1} }
+ \fp_compare:nNnT \l_tmpa_fp < \l__mermap_supply_west_fp
+ { \fp_set_eq:NN \l__mermap_supply_west_fp \l_tmpa_fp }
+ \fp_compare:nNnT \l_tmpa_fp > \l__mermap_supply_east_fp
+ { \fp_set_eq:NN \l__mermap_supply_east_fp \l_tmpa_fp }
+ }
+ }
+
+
+\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_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_tmpa_clist
+ },
+ area .value_required:n = true,
+ add~area .code:n =
+ {
+ \clist_set:Nn \l_tmpa_clist { #1 }
+ \__mermap_supply_add_area_clist:N \l_tmpa_clist
+ },
+ 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_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_tmpa_fp}
+ \fp_set:Nn \l__mermap_supply_height_fp{\l__mermap_supply_height_fp*\l_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_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_tmpb_fp { ln(\l_tmpa_fp)/ln(2) }
+ \fp_set:Nn \l_tmpb_fp { round(\l_tmpb_fp)/\l_tmpb_fp }
+ \fp_set:Nn \l_tmpb_fp { \l_tmpa_fp^(\l_tmpb_fp-1+0.0000001) }
+ \dim_set:Nn \l__mermap_tile_size_dim { \fp_to_dim:n { \l__mermap_flex_tile_size_dim / \l_tmpb_fp }}
+ \fp_set:Nn \l__mermap_supply_width_fp { \l__mermap_supply_width_fp * \l_tmpb_fp + (#1)/\l__mermap_tile_size_dim }
+ \fp_set:Nn \l__mermap_supply_height_fp { \l__mermap_supply_height_fp * \l_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}},
+ python .code:n = {
+ \tl_set:Nx \l__mermap_python {#1~maptiles.texpy}
+ },
+ }
+
+\keys_set:nn { mermap }
+ {
+ definition~prefix = maps/,
+ 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 }
+ \group_begin:
+ \def\@latex@warning@no@line##1{}% suppress filecontents warning
+ \file_input:n {\mrcpkgprefix mercatorpy.def}
+ \group_end:
+ \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_tmpa_tl {#1}
+ \tl_trim_spaces:N \l_tmpa_tl
+ \str_set:Nx \l__mermap_definition_postfix_str {\tl_to_str:N \l_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_tmpa_tl {#2}
+ \tl_trim_spaces:N \l_tmpa_tl
+ \tl_if_empty:NT \l_tmpa_tl
+ {
+ \int_gincr:N \g__mermap_automap_int
+ \tl_set:Nx \l_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
+ }
+ }
+ \str_set:Nx \l__mermap_definition_postfix_str {\tl_to_str:N \l_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 }
+ \tl_set:Nx \l_tmpa_tl { \str_use:N\l__mermap_definition_id_str }
+ \prop_if_in:NVT \g__mermap_definition_prop \l_tmpa_tl
+ {
+ \msg_warning:nnx { mercatormap }{ definition-id-used }{ \tl_use:N \l_tmpa_tl }
+ }
+ \prop_gput:NVn \g__mermap_definition_prop \l_tmpa_tl {}
+ \bool_if:NT \l__mermap_script_activated_bool
+ {
+ \__mermap_supplymap_call:
+ }
+ %\dim_gset_eq:NN \g_tmpa_dim \l__mermap_tile_size_dim
+ \group_end:
+ %\dim_set_eq:NN \l__mermap_tile_size_dim \g_tmpa_dim
+ }
+
+\NewDocumentCommand \mrcsupplymap { O{} m }
+ {
+ \__mermap_create_definition_id:n {#2}
+ \__mermap_supplymap:n {#1}
+ }
+
+
+\msg_new:nnn { mercatormap }{ shell-escape }
+ { You~must~invoke~LaTeX~with~the~--shell-escape~flag~to~produce~map~'#1'. }
+
+\msg_new:nnn { mercatormap }{ target-resource }
+ { Target~and~produced~resource~are~different~for~map~'#1'. }
+
+\msg_new:nnn { mercatormap }{ definition-production }
+ { Map~definition~file~not~produced~for~map~'#1'. }
+
+\cs_new:Npn \__mermap_supplymap_call:
+ {
+ \tl_set_eq:Nc \l_tmpa_tl {
+ c__mermap_supply_call_\l__mermap_supply_type_tl _tl }
+ \tl_set:Nx \l__mermap_supply_call_tl \l_tmpa_tl
+ \tl_set:Nx \l__mermap_mdfivesum_tl { \pdf@mdfivesum{\l__mermap_supply_call_tl} }
+ \tl_clear:N \l__mermap_last_mdfivesum_tl
+ \file_if_exist_input:n {\l__mermap_definition_id_str.md5}
+ \str_if_eq:VVTF \l__mermap_mdfivesum_tl \l__mermap_last_mdfivesum_tl
+ {
+ \file_if_exist:nF {\l__mermap_definition_id_str.def}
+ {
+ \__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}
+ \msg_warning:nnx { mercatormap }{ target-resource }{ \l__mermap_definition_id_str }
+ }
+ }
+ {
+ \__mermap_write_mdfive:n {false}
+ \msg_warning:nnx { mercatormap }{ definition-production }{ \l__mermap_definition_id_str }
+ }
+ }
+ {
+ \__mermap_write_mdfive:n {false}
+ \msg_warning: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_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_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_tmpa_fp
+ {
+ min ( \l__mermap_network_pieces_int, round((#1)/\l__mermap_network_distance_dim) )
+ }
+ \fp_set:Nn \l_tmpb_fp { (#2)/\l_tmpa_fp }
+ \fp_set:Nn \l_tmpa_fp { floor(ln(\l_tmpb_fp)/ln(10)) }
+ \fp_compare:nNnTF {\l_tmpa_fp} < {0}
+ {
+ \fp_compare:nNnTF {\l_tmpa_fp} > {-5}
+ {
+ \use:x
+ {
+ \exp_not:N\keys_set:nn { mermap }{ format~angle=decimal\fp_to_int:N\l_tmpa_fp}
+ }
+ }
+ {
+ \keys_set:nn { mermap }{ format~angle=decimal }
+ }
+ }
+ {
+ \keys_set:nn { mermap }{ format~angle=decimal-0 }
+ }
+ \fp_set:Nn \l_tmpa_fp { 10^\l_tmpa_fp }
+ \fp_set:Nn \l_tmpb_fp { \l_tmpb_fp/\l_tmpa_fp }
+ \fp_compare:nNnTF {abs(\l_tmpb_fp-1)} < {abs(\l_tmpb_fp-2)}
+ {
+ \fp_compare:nNnTF {abs(\l_tmpb_fp-1)} < {abs(\l_tmpb_fp-5)}
+ {
+ \fp_set:Nn \l__mermap_result_fp {\l_tmpa_fp}
+ }
+ {
+ \fp_set:Nn \l__mermap_result_fp {5*\l_tmpa_fp}
+ }
+ }
+ {
+ \fp_compare:nNnTF {abs(\l_tmpb_fp-2)} < {abs(\l_tmpb_fp-5)}
+ {
+ \fp_set:Nn \l__mermap_result_fp {2*\l_tmpa_fp}
+ }
+ {
+ \fp_set:Nn \l__mermap_result_fp {5*\l_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_tmpa_fp { ceil(\l__mermap_mapsouth_fp/\l__mermap_result_fp)*\l__mermap_result_fp}
+ \fp_compare:nNnT {\l_tmpa_fp-\l__mermap_mapsouth_fp} < {1e-10}
+ {
+ \fp_add:Nn \l_tmpa_fp {\l__mermap_result_fp}
+ }
+ \fp_while_do:nNnn {\l_tmpa_fp} < {\l__mermap_mapnorth_fp}
+ {
+ \tl_set:Nn \l_tmpa_tl {\fp_use:N\l_tmpa_fp}
+ \draw[gray,very~thin] (mrc~cs\c_colon_str lat=\l_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_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_tmpa_tl}}
+ ;
+ \fp_add:Nn \l_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_tmpa_fp { ceil(\l__mermap_mapwest_fp/\l__mermap_result_fp)*\l__mermap_result_fp}
+ \fp_compare:nNnT {\l_tmpa_fp-\l__mermap_mapwest_fp} < {1e-10}
+ {
+ \fp_add:Nn \l_tmpa_fp {\l__mermap_result_fp}
+ }
+ \fp_while_do:nNnn {\l_tmpa_fp} < {\l__mermap_mapeast_fp}
+ {
+ \tl_set:Nn \l_tmpa_tl {\fp_use:N\l_tmpa_fp}
+ \draw[gray,very~thin] (mrc~cs\c_colon_str lon=\l_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_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_tmpa_tl}}
+ ;
+ \fp_add:Nn \l_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_tmpa_fp { #1 }
+ \fp_compare:nNnTF \l_tmpa_fp < 5
+ {
+ \SI[round-mode=figures,round-precision=3,detect-all]{\fp_to_decimal:n{1000*\l_tmpa_fp}}{\meter}
+ }
+ {
+ \SI[round-mode=figures,round-precision=3,detect-all]{\fp_to_decimal:N \l_tmpa_fp}{\kilo\meter}
+ }
+ }
+
+
+\cs_new_nopar:Npn \__mermap_pretty_length:n #1
+ {
+ \fp_set:Nn \l_tmpa_fp { (#1)*\l__mermap_scale_fp }
+ \fp_compare:nNnTF \l_tmpa_fp < 5
+ {
+ \SI[round-mode=figures,round-precision=3,detect-all]{\fp_to_decimal:n{1000*\l_tmpa_fp}}{\meter}
+ }
+ {
+ \SI[round-mode=figures,round-precision=3,detect-all]{\fp_to_decimal:N \l_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_tmpa_fp {floor(#1)}
+ \fp_set:Nn \l_tmpb_fp {round((#1-\l_tmpa_fp)*60)}
+ \ang[add-arc-degree-zero,add-arc-minute-zero]
+ {
+ \fp_to_int:N \l_tmpa_fp ;
+ \fp_to_int:N \l_tmpb_fp ;
+ }
+ }
+
+
+\cs_new_nopar:Npn \__mermap_format_angle_second:n #1
+ {
+ \fp_set:Nn \l_tmpa_fp {floor(#1)}
+ \fp_set:Nn \l_tmpb_fp {floor((#1-\l_tmpa_fp)*60)}
+ \ang[add-arc-degree-zero,add-arc-minute-zero]
+ {
+ \fp_to_int:N \l_tmpa_fp ;
+ \fp_to_int:N \l_tmpb_fp ;
+ \fp_to_int:n {round(((#1-\l_tmpa_fp)*60-\l_tmpb_fp)*60)}
+ }
+ }
+
+\NewDocumentCommand{\mrcformlat}{ o m }
+ {
+ \group_begin:
+ \IfNoValueF {#1}
+ { \keys_set:nn { mermap } {#1} }
+ \fp_set:Nn \l_tmpa_fp {#2}
+ \fp_compare:nNnTF \l_tmpa_fp < 0
+ {
+ \tl_set:Nx \l__mermap_temp_tl {\fp_to_decimal:n{-\l_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_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_tmpa_fp {#2-360*floor((#2+180)/360)}
+ \fp_compare:nNnTF \l_tmpa_fp < 0
+ {
+ \tl_set:Nx \l__mermap_temp_tl {\fp_to_decimal:n{-\l_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_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_tmpa_fp {0}
+ \fp_set:Nn \l_tmpb_fp {0}
+ }
+ {
+ \fp_set:Nn \l_tmpa_fp {#3*(#5)}
+ \tl_if_empty:nTF {#6}
+ {
+ \fp_set:Nn \l_tmpb_fp {#4*(#5)}
+ }
+ {
+ \fp_set:Nn \l_tmpb_fp {#4*(#6)}
+ }
+ }
+ \tl_set:Nx \l__mermap_scalebar_at_tl
+ {
+ {([xshift=\fp_to_dim:N\l_tmpa_fp,yshift=\fp_to_dim:N\l_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 = {([xshift=-10mm,yshift=5mm]mrcmap.south~east)},
+ %placement = above~left,
+ 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_tmpa_fp {\l__mermap_scalebar_width_fp/\l__mermap_scale_fp} % Breite
+ \pgfpathrectangle{\pgfpoint{0pt}{0pt}}
+ {\pgfpoint{\fp_to_dim:N\l_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_tmpa_fp {\l__mermap_scalebar_width_fp/\l__mermap_scale_fp}
+ }
+ \fp_set:Nn \l_tmpb_fp {\l_tmpa_fp/\l__mermap_scalebar_partitions_int}
+ \bool_if:NTF \l__mermap_scalebar_double_bool
+ {
+ \int_set:Nn \l_tmpa_int {1}
+ \dim_set:Nn \l_tmpb_dim {\l__mermap_scalebar_height_dim/2}
+ \dim_set:Nn \l_tmpa_dim {0.2pt-\l_tmpb_dim}
+ \int_compare:nNnTF \l__mermap_scalebar_partitions_int = 1
+ {
+ \pgfpathrectangle{\pgfpoint{0.2pt}{\l_tmpb_dim}}
+ {\pgfpoint{\fp_to_dim:n{\l_tmpb_fp-0.4pt}}{\l_tmpa_dim}}
+ }
+ {
+ \pgfpathrectangle{\pgfpoint{0.2pt}{\l_tmpb_dim}}
+ {\pgfpoint{\fp_to_dim:n{\l_tmpb_fp-0.2pt}}{\l_tmpa_dim}}
+ }
+ \int_while_do:nNnn \l_tmpa_int < \l__mermap_scalebar_partitions_int
+ {
+ \dim_set:Nn \l_tmpa_dim {-\l_tmpa_dim}
+ \int_compare:nNnTF {\l_tmpa_int+1} = \l__mermap_scalebar_partitions_int
+ {
+ \pgfpathrectangle{\pgfpoint{\fp_to_dim:n{\l_tmpa_int*\l_tmpb_fp}}{\l_tmpb_dim}}
+ {\pgfpoint{\fp_to_dim:n{\l_tmpb_fp-0.2pt}}{\l_tmpa_dim}}
+ }
+ {
+ \pgfpathrectangle{\pgfpoint{\fp_to_dim:n{\l_tmpa_int*\l_tmpb_fp}}{\l_tmpb_dim}}
+ {\pgfpoint{\fp_to_dim:N\l_tmpb_fp}{\l_tmpa_dim}}
+ }
+ \int_incr:N \l_tmpa_int
+ }
+ }
+ {
+ \int_set:Nn \l_tmpa_int {1}
+ \dim_set:Nn \l_tmpa_dim {\l__mermap_scalebar_height_dim-0.4pt}
+ \int_while_do:nNnn \l_tmpa_int < \l__mermap_scalebar_partitions_int
+ {
+ \int_compare:nNnTF {\l_tmpa_int+1} = \l__mermap_scalebar_partitions_int
+ {
+ \pgfpathrectangle{\pgfpoint{\fp_to_dim:n{\l_tmpa_int*\l_tmpb_fp}}{0.2pt}}
+ {\pgfpoint{\fp_to_dim:n{\l_tmpb_fp-0.2pt}}{\l_tmpa_dim}}
+ }
+ {
+ \pgfpathrectangle{\pgfpoint{\fp_to_dim:n{\l_tmpa_int*\l_tmpb_fp}}{0.2pt}}
+ {\pgfpoint{\fp_to_dim:N\l_tmpb_fp}{\l_tmpa_dim}}
+ }
+ \int_add:Nn \l_tmpa_int {2}
+ }
+ }
+ \__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
+
+\fp_new:N \l__mermap_marker_angle_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_pictocontents_tl
+\tl_new:N \l__mermap_marker_type_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,
+ % name .meta:nn = {mermap/marker}{contents={#1},alias={#1}},
+ uuid .tl_set:N = \l__mermap_marker_uuid_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,
+ 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} },
+ 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,
+ % name = noname,
+ contents =,
+ alias = noname,
+ pictocontents =,
+ angle = 90,
+ shift = 0pt,
+ fill = gray!20,
+ draw = gray,
+ text = black,
+ radius = 3mm,
+ inner~radius = 2.25mm,
+ path~style =,
+ node~style =,
+ font = \sffamily\small,
+ type = classic,
+ uuid =,
+ category =,
+ show = 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}
+\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\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.
+ }
+
+
+\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]\mrcmarkercontents}] {};
+ }
+
+\__mermap_new_marker_type:nn {pin}
+ {
+ \path[fill=mrcmarkerfill,draw=none,fill~opacity=0.7]
+ (0,0) -- (0.1,0.5) -- (-0.1,0.5) -- 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]
+ (pin_node) at (0,0.5) {\mrcmarkercontents};
+ \path[draw=mrcmarkerdraw,fill=none,line~join=round,mrcpathstyle]
+ (0,0) -- (0.1,0.5) -- (pin_node.south~east) -- (pin_node.north~east)
+ -- (pin_node.north~west) -- (pin_node.south~west)
+ -- (-0.1,0.5) [line~join=bevel] -- cycle;
+ }
+
+\__mermap_new_marker_type:nn {pinflip}
+ {
+ \path[fill=mrcmarkerfill,draw=none,fill~opacity=0.7]
+ (0,0) -- (-0.1,-0.5) -- (0.1,-0.5) -- 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]
+ (pin_node) at (0,-0.5) {\mrcmarkercontents};
+ \path[draw=mrcmarkerdraw,fill=none,line~join=round,mrcpathstyle]
+ (0,0) -- (-0.1,-0.5) -- (pin_node.north~west) -- (pin_node.south~west)
+ -- (pin_node.south~east) -- (pin_node.north~east)
+ -- (0.1,-0.5) [line~join=bevel] -- cycle;
+ }
+
+
+\cs_new_nopar:Npn \__mermap_tikz_drop_path:n #1
+ {
+ \tl_set:Nn \l_tmpa_tl {\fp_to_dim:N\l__mermap_marker_radius_fp}
+ \tl_set:Nn \l_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
+ }
+ \pgfpathmoveto{\pgfpoint{0pt}{\fp_to_dim:n{-2*\l__mermap_marker_radius_fp-\l__mermap_marker_shift_fp}}}
+ \pgfpathcurveto{\pgfpoint{\l_tmpb_tl}{-\l_tmpa_tl}}{\pgfpoint{\l_tmpa_tl}{-\l_tmpb_tl}}
+ {\pgfpoint{\l_tmpa_tl}{0pt}}
+ \pgfpathcurveto{\pgfpoint{\l_tmpa_tl}{\l_tmpb_tl}}{\pgfpoint{\l_tmpb_tl}{\l_tmpa_tl}}
+ {\pgfpoint{0pt}{\l_tmpa_tl}}
+ \pgfpathcurveto{\pgfpoint{-\l_tmpb_tl}{\l_tmpa_tl}}{\pgfpoint{-\l_tmpa_tl}{\l_tmpb_tl}}
+ {\pgfpoint{-\l_tmpa_tl}{0pt}}
+ \pgfpathcurveto{\pgfpoint{-\l_tmpa_tl}{-\l_tmpb_tl}}{\pgfpoint{-\l_tmpb_tl}{-\l_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_tmpa_box {\mrcmarkercontents}
+ \fp_compare:nNnT {\box_wd:N \l_tmpa_box} > {1.5*\l__mermap_marker_radius_fp}
+ {
+ \box_resize_to_wd_and_ht:Nnn \l_tmpa_box
+ {\fp_to_dim:n {1.5*\l__mermap_marker_radius_fp}}
+ {\box_ht:N \l_tmpa_box}
+ }
+ \box_use_drop:N \l_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]
+ 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]
+ 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,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_tmpa_tl {\fp_to_dim:N\l__mermap_marker_radius_fp}
+ \path[draw=mrcmarkerdraw,very~thin]
+ (45 \c_colon_str \l_tmpa_tl)--(225\c_colon_str \l_tmpa_tl)
+ (135\c_colon_str \l_tmpa_tl)--(315\c_colon_str \l_tmpa_tl);
+ \path[draw=mrcmarkerdraw,fill=mrcmarkerfill,mrcpathstyle,even~odd~rule]
+ circle (\l_tmpa_tl) circle (\fp_to_dim:N\l__mermap_marker_inner_radius_fp);
+ }
+
+\__mermap_new_marker_type:nn {markx}
+ {
+ \tl_set:Nn \l_tmpa_tl {\fp_to_dim:N\l__mermap_marker_radius_fp}
+ \path[line~join=bevel,draw=mrcmarkerdraw,fill=mrcmarkerfill,mrcpathstyle]
+ (0,0) -- (35 \c_colon_str \l_tmpa_tl) -- (55 \c_colon_str \l_tmpa_tl) -- cycle
+ (0,0) -- (125 \c_colon_str \l_tmpa_tl) -- (145 \c_colon_str \l_tmpa_tl) -- cycle
+ (0,0) -- (215 \c_colon_str \l_tmpa_tl) -- (235 \c_colon_str \l_tmpa_tl) -- cycle
+ (0,0) -- (305 \c_colon_str \l_tmpa_tl) -- (325 \c_colon_str \l_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_delta_lambda_fp
+\fp_new:N \l__mermap_delta_phi_fp
+\fp_new:N \l__mermap_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
+
+\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:Npn \__mermap_draw_orthodrome:nnnnn #1#2#3#4#5
+ {
+ \__mermap_tikz_path_begin:n { draw,mermap_every_route,#1 }
+ \fp_set:Nn \l__mermap_a_x_fp { cosd(#3)*cosd(#2) }
+ \fp_set:Nn \l__mermap_a_y_fp { sind(#3)*cosd(#2) }
+ \fp_set:Nn \l__mermap_a_z_fp { sind(#2) }
+ \fp_set:Nn \l__mermap_b_x_fp { cosd(#5)*cosd(#4) }
+ \fp_set:Nn \l__mermap_b_y_fp { sind(#5)*cosd(#4) }
+ \fp_set:Nn \l__mermap_b_z_fp { sind(#4) }
+
+ \fp_set:Nn \l_tmpa_fp { sind(#2)*sind(#4) + cosd(#2)*cosd(#4)*cosd(#5-(#3)) }
+ \fp_set:Nn \l__mermap_psi_fp { acosd(\l_tmpa_fp) }
+ \fp_set:Nn \l_tmpb_fp { sind(\l__mermap_psi_fp) }
+
+ \fp_set:Nn \l__mermap_b_x_fp { (\l__mermap_b_x_fp - \l_tmpa_fp*\l__mermap_a_x_fp)/\l_tmpb_fp }
+ \fp_set:Nn \l__mermap_b_y_fp { (\l__mermap_b_y_fp - \l_tmpa_fp*\l__mermap_a_y_fp)/\l_tmpb_fp }
+ \fp_set:Nn \l__mermap_b_z_fp { (\l__mermap_b_z_fp - \l_tmpa_fp*\l__mermap_a_z_fp)/\l_tmpb_fp }
+
+ \__mermap_pgf_moveto_point:nn {#2}{#3}
+ \int_set:Nn \l_tmpa_int {1}
+ \int_until_do:nNnn \l_tmpa_int > \l__mermap_samples_int
+ {
+ \fp_set:Nn \l_tmpa_fp { \l__mermap_psi_fp*\l_tmpa_int/\l__mermap_samples_int }
+ \fp_set:Nn \l_tmpb_fp { sind(\l_tmpa_fp) }
+ \fp_set:Nn \l_tmpa_fp { cosd(\l_tmpa_fp) }
+ \fp_set:Nn \l__mermap_t_x_fp { \l_tmpa_fp*\l__mermap_a_x_fp + \l_tmpb_fp*\l__mermap_b_x_fp }
+ \fp_set:Nn \l__mermap_t_y_fp { \l_tmpa_fp*\l__mermap_a_y_fp + \l_tmpb_fp*\l__mermap_b_y_fp }
+ \fp_set:Nn \l__mermap_t_z_fp { \l_tmpa_fp*\l__mermap_a_z_fp + \l_tmpb_fp*\l__mermap_b_z_fp }
+ \pgfpathlineto{\__mermap_unit_sphere_point:nnn {\l__mermap_t_x_fp}{\l__mermap_t_y_fp}{\l__mermap_t_z_fp}}
+ \int_incr:N \l_tmpa_int
+ }
+ \__mermap_tikz_path_end:
+ }
+
+
+\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_tmpa_fp { tand(#1) }
+ \fp_set:Nn \l_tmpb_fp { \l__mermap_delta_lambda_fp*cosd(#1)
+ /( 1 + (\l_tmpa_fp + (1+2*\l_tmpa_fp*\l_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_tmpb_fp*\l_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 }
+ }
+
+
+
+%---- supplier -----------------------------------------------------------------
+
+\file_input:n { \mrcpkgprefix mercatorsupplier.def }
diff --git a/Master/texmf-dist/tex/latex/mercatormap/mercatorpy.def b/Master/texmf-dist/tex/latex/mercatormap/mercatorpy.def
new file mode 100644
index 00000000000..fe608f47b49
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/mercatormap/mercatorpy.def
@@ -0,0 +1,535 @@
+\begin{filecontents*}[overwrite]{maptiles.texpy}
+"""
+The LaTeX package mercatormap - version 1.00 (2020/04/20)
+maptiles.texpy: Python script for map tile download
+
+-------------------------------------------------------------------------------------------
+Copyright (c) 2020 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
+"""
+
+import argparse
+import math
+import os
+import requests
+from pathlib import Path
+from PIL import Image
+
+
+packageversion = '1.00 (2020/04/20)'
+
+
+def gd(x):
+ return math.atan(math.sinh(x))
+
+
+def arggd(x):
+ return math.asinh(math.tan(x))
+
+
+def rad2planar(lon_rad, lat_rad):
+ x = 0.5*lon_rad/math.pi + 0.5
+ y = 0.5*arggd(lat_rad)/math.pi + 0.5
+ return (x, y)
+
+
+def deg2planar(lon_deg, lat_deg):
+ return rad2planar(math.radians(lon_deg), math.radians(lat_deg))
+
+
+def planar2rad(x, y):
+ lon_rad = math.pi*(2*x-1)
+ lat_rad = gd(math.pi*(2*y-1))
+ return (lon_rad, lat_rad)
+
+
+def planar2deg(x, y):
+ (lon_rad, lat_rad) = planar2rad(x, y)
+ return (math.degrees(lon_rad), math.degrees(lat_rad))
+
+
+def download(session, url, filename, overwrite=False):
+ local_file = Path(filename)
+ if local_file.is_file() and not overwrite:
+ return
+ print(url+' -> '+filename)
+ r = session.get(url)
+ r.raise_for_status()
+ with open(filename, 'wb') as handler:
+ handler.write(r.content)
+ return
+
+
+def makeparentdirs(afile):
+ directory = Path(os.path.abspath(afile)).parent
+ if not directory.is_dir():
+ os.makedirs(directory)
+
+
+class MapDefinition(object):
+ def __init__(self, args, west, east, north, south, zoom, x_1, y_1, x_2, y_2,
+ width, height, west_offset, north_offset, south_offset):
+ self.west = west
+ self.east = east
+ self.north = north
+ self.south = south
+ self.zoom = zoom
+ self.x_1 = x_1
+ self.y_1 = y_1
+ self.x_2 = x_2
+ self.y_2 = y_2
+ self.width = width
+ self.height= height
+ self.west_offset = west_offset
+ self.north_offset = north_offset
+ self.south_offset = south_offset
+ self.n = 2 ** self.zoom
+ self.local_file_prefix = 'tiles/tile_'
+ self.attribution = args.attribution
+ self.attributionprint = args.attributionprint
+ self.pixel = args.pixel
+ self.pixel_width = round(self.width*self.pixel)
+ self.pixel_height = round(self.height*self.pixel)
+ self.tilesize = args.tilesize
+
+
+ @classmethod
+ def construct_from_boundaries_rad(cls, args, zoom, west_rad, east_rad, north_rad, south_rad):
+ if zoom<0:
+ zoom = 0
+ if west_rad>=east_rad:
+ east_rad += 2*math.pi*math.ceil(0.5*(west_rad-east_rad)/math.pi+1e-10)
+ max_lat = gd(math.pi)-1e-10
+ if north_rad<south_rad:
+ (north_rad, south_rad) = (south_rad, north_rad)
+ if north_rad > max_lat:
+ north_rad = max_lat
+ if south_rad < -max_lat:
+ south_rad = -max_lat
+ P = 2**(zoom-1)/math.pi
+ a1 = (west_rad+math.pi)*P
+ b1 = (math.pi-arggd(north_rad))*P
+ a2 = (east_rad+math.pi)*P
+ b2 = (math.pi-arggd(south_rad))*P
+ x1 = math.floor(a1)
+ y1 = math.floor(b1)
+ x2 = math.ceil(a2)-1
+ y2 = math.ceil(b2)-1
+ width = a2-a1
+ height = b2-b1
+ west_offset = a1-x1
+ north_offset = b1-y1
+ south_offset = y2-b2+1
+ return cls(args, west_rad, east_rad, north_rad, south_rad, zoom, x1, y1, x2, y2,
+ width, height, west_offset, north_offset, south_offset )
+
+
+ @classmethod
+ def construct_from_boundaries_deg(cls, args, zoom, west_deg, east_deg, north_deg, south_deg):
+ return cls.construct_from_boundaries_rad(args,
+ zoom,math.radians(west_deg),math.radians(east_deg),
+ math.radians(north_deg),math.radians(south_deg))
+
+
+ @classmethod
+ def construct_from_boundaries_args(cls, args):
+ return cls.construct_from_boundaries_rad(args,
+ args.zoom,math.radians(args.west),math.radians(args.east),math.radians(args.north),math.radians(args.south))
+
+
+ @classmethod
+ def construct_from_reference_rad(cls, args, zoom, width, height,
+ ref_lon_rad, ref_lat_rad, xalign, yalign):
+ if zoom<0:
+ zoom = 0
+ P = 2**(zoom-1)/math.pi
+ ac = (ref_lon_rad+math.pi)*P
+ bc = (math.pi-arggd(ref_lat_rad))*P
+ a1 = ac - (1+xalign)/2*width
+ a2 = a1 + width
+ b1 = bc - (1+yalign)/2*height
+ b2 = b1 + height
+ west_rad = a1/P - math.pi
+ north_rad = gd(math.pi-b1/P)
+ east_rad = a2/P - math.pi
+ south_rad = gd(math.pi-b2/P)
+ x1 = math.floor(a1)
+ y1 = math.floor(b1)
+ x2 = math.ceil(a2)-1
+ y2 = math.ceil(b2)-1
+ west_offset = a1-x1
+ north_offset = b1-y1
+ south_offset = y2-b2+1
+ return cls(args, west_rad, east_rad, north_rad, south_rad, zoom, x1, y1, x2, y2,
+ width, height, west_offset, north_offset, south_offset )
+
+
+ @classmethod
+ def construct_from_reference_deg(cls, args, zoom, width, height,
+ ref_lon_deg, ref_lat_deg, xalign, yalign):
+ return cls.construct_from_center_rad(args, zoom, width, height,
+ math.radians(ref_lon_deg), math.radians(ref_lat_deg), xalign, yalign)
+
+
+ @classmethod
+ def construct_from_reference_args(cls, args):
+ return cls.construct_from_reference_rad(args, args.zoom, args.width, args.height,
+ math.radians(args.longitude), math.radians(args.latitude), args.xalign, args.yalign)
+
+
+ @classmethod
+ def construct_to_fit_region_rad(cls, args, width, height, reg_west_rad, reg_east_rad,
+ reg_north_rad, reg_south_rad, xalign, yalign):
+ if reg_west_rad>=reg_east_rad:
+ reg_east_rad += 2*math.pi*math.ceil(0.5*(reg_west_rad-reg_east_rad)/math.pi+1e-10)
+ max_lat = gd(math.pi)-1e-10
+ if reg_north_rad<reg_south_rad:
+ (reg_north_rad, reg_south_rad) = (reg_south_rad, reg_north_rad)
+ if reg_north_rad > max_lat:
+ reg_north_rad = max_lat
+ if reg_south_rad < -max_lat:
+ reg_south_rad = -max_lat
+ zoom = max( 0, 1 + math.floor( math.log2( math.pi *
+ min( width/(reg_east_rad-reg_west_rad), height/(arggd(reg_north_rad)-arggd(reg_south_rad)))
+ )))
+ P = 2**(zoom-1)/math.pi
+
+ if xalign<0:
+ a1 = (reg_west_rad+math.pi)*P
+ a2 = a1 + width
+ elif xalign>0:
+ a2 = (reg_east_rad+math.pi)*P
+ a1 = a2 - width
+ else:
+ a1 = ((reg_west_rad+reg_east_rad)/2+math.pi)*P - width/2
+ a2 = a1 + width
+
+ if yalign<0:
+ b1 = (math.pi-arggd(reg_north_rad))*P
+ b2 = b1 + height
+ elif yalign>0:
+ b2 = (math.pi-arggd(reg_south_rad))*P
+ b1 = b2 - height
+ else:
+ b1 = (math.pi-(arggd(reg_north_rad)+arggd(reg_south_rad))/2)*P - height/2
+ b2 = b1 + height
+ west_rad = a1/P - math.pi
+ north_rad = gd(math.pi-b1/P)
+ east_rad = a2/P - math.pi
+ south_rad = gd(math.pi-b2/P)
+ x1 = math.floor(a1)
+ y1 = math.floor(b1)
+ x2 = math.ceil(a2)-1
+ y2 = math.ceil(b2)-1
+ west_offset = a1-x1
+ north_offset = b1-y1
+ south_offset = y2-b2+1
+ return cls(args, west_rad, east_rad, north_rad, south_rad, zoom, x1, y1, x2, y2,
+ width, height, west_offset, north_offset, south_offset )
+
+
+ @classmethod
+ def construct_to_fit_region_deg(cls, args, width, height,
+ reg_west_deg, reg_east_deg, reg_north_deg, reg_south_deg,
+ xalign, yalign):
+ return cls.construct_to_fit_region_rad(args, width, height,
+ math.radians(reg_west_deg),math.radians(reg_east_deg),
+ math.radians(reg_north_deg),math.radians(reg_south_deg),
+ xalign, yalign)
+
+
+ @classmethod
+ def construct_to_fit_region_args(cls, args):
+ return cls.construct_to_fit_region_rad(args, args.width, args.height,
+ math.radians(args.west),math.radians(args.east),
+ math.radians(args.north),math.radians(args.south),
+ args.xalign, args.yalign)
+
+
+ def get_tile_quantity(self):
+ return (self.x_2-self.x_1+1)*(self.y_2-self.y_1+1)
+
+
+ def get_pixel_quantity(self):
+ return self.pixel_width*self.pixel_height
+
+
+ def download_tiles(self, url_format, local_file_prefix):
+ self.local_file_prefix = local_file_prefix
+ makeparentdirs(local_file_prefix)
+ with requests.Session() as s:
+ s.headers.update(dict(referer = 'mercatormap/'+packageversion))
+ try:
+ for xx in range(self.x_1, self.x_2+1):
+ x = xx % self.n
+ for y in range(self.y_1, self.y_2+1):
+ if (y>=0) and (y<self.n):
+ url = url_format.format(x=x, y=y, z=self.zoom)
+ filename = local_file_prefix + '_{z}_{x}_{y}.png'.format(x=x, y=y, z=self.zoom)
+ download(s,url,filename)
+ except requests.exceptions.RequestException as err:
+ print('Download error:', err)
+ return False
+ return True
+
+
+ def merge_map(self, map_definition, local_file_prefix):
+ makeparentdirs(map_definition)
+ new_im = Image.new('RGB', (self.pixel_width, self.pixel_height), 'white')
+ xoff = -round(self.west_offset*self.pixel)
+ for xx in range(self.x_1, self.x_2+1):
+ x = xx % self.n
+ yoff = -round(self.north_offset*self.pixel)
+ for y in range(self.y_1, self.y_2+1):
+ if (y>=0) and (y<self.n):
+ filename = local_file_prefix + '_{z}_{x}_{y}.png'.format(x=x, y=y, z=self.zoom)
+ new_im.paste(Image.open(filename), (xoff,yoff))
+ yoff+=self.pixel
+ xoff+=self.pixel
+ new_im.save(map_definition+'.png', optimize=True)
+ return True
+
+
+ def download_wms_map(self, url_format, map_definition):
+ makeparentdirs(map_definition)
+ # bbox in tiles for given zoom
+ xmin = self.x_1+self.west_offset
+ xmax = xmin+self.width
+ ymin = self.y_1+self.north_offset
+ ymax = ymin+self.height
+
+ # global scale bbox
+ f = math.pi*6378137
+ xmin = (2*xmin/self.n-1)*f
+ xmax = (2*xmax/self.n-1)*f
+ (ymin, ymax) = (ymax, ymin) # switch ymin/ymax
+ ymin = (1-2*ymin/self.n)*f
+ ymax = (1-2*ymax/self.n)*f
+
+ url = url_format.format(xmin=xmin, ymin=ymin, xmax=xmax, ymax=ymax,
+ width=self.pixel_width, height=self.pixel_height)
+ filename = map_definition+'.png'
+ with requests.Session() as s:
+ s.headers.update(dict(referer = 'mercatormap/'+packageversion))
+ try:
+ download(s,url,filename,True)
+ except requests.exceptions.RequestException as err:
+ print('Download error:', err)
+ return False
+ return True
+
+
+ def save_map(self, map_definition, tiles=False, merge=False, wms=False):
+ makeparentdirs(map_definition)
+ with open(map_definition+'.def', "w", encoding="utf-8") as desc:
+ desc.write(f'% generated by mercatormap maptiles {packageversion}\n')
+ desc.write('\\mrcdefinemap{\n')
+ desc.write(f' west={math.degrees(self.west)},\n')
+ desc.write(f' east={math.degrees(self.east)},\n')
+ desc.write(f' north={math.degrees(self.north)},\n')
+ desc.write(f' south={math.degrees(self.south)},\n')
+ desc.write(f' zoom={self.zoom},\n')
+ desc.write(f' xmin={self.x_1},\n')
+ desc.write(f' ymin={self.y_1},\n')
+ desc.write(f' xmax={self.x_2},\n')
+ desc.write(f' ymax={self.y_2},\n')
+ desc.write(f' pixelwidth={self.pixel_width},\n')
+ desc.write(f' pixelheight={self.pixel_height},\n')
+ desc.write(f' westoffset={self.west_offset},\n')
+ desc.write(f' northoffset={self.north_offset},\n')
+ desc.write(f' southoffset={self.south_offset},\n')
+ desc.write(f' basename={self.local_file_prefix},\n')
+ if self.attribution!=None:
+ desc.write(' attribution={'+self.attribution+'},\n')
+ if self.attributionprint!=None:
+ desc.write(' attribution print={'+self.attributionprint+'},\n')
+ if self.tilesize!=None:
+ desc.write(f' tile size={self.tilesize},\n')
+ if wms:
+ desc.write(f' resource=wmsmap,\n')
+ elif merge:
+ desc.write(f' resource=mergedmap,\n')
+ elif tiles:
+ desc.write(f' resource=tiles,\n')
+ else:
+ desc.write(f' resource=none,\n')
+ desc.write('}\n')
+ return
+
+
+ def print_description(self):
+ print('------ map description (class) ------')
+ print(f'west = {math.degrees(self.west)}')
+ print(f'east = {math.degrees(self.east)}')
+ print(f'north = {math.degrees(self.north)}')
+ print(f'south = {math.degrees(self.south)}')
+ print(f'zoom = {self.zoom}')
+ print(f'X_1 = {self.x_1}')
+ print(f'Y_1 = {self.y_1}')
+ print(f'X_2 = {self.x_2}')
+ print(f'Y_2 = {self.y_2}')
+ print(f'width = {self.width}')
+ print(f'height = {self.height}')
+ print(f'd_west = {self.west_offset}')
+ print(f'd_north = {self.north_offset}')
+ print(f'd_south = {self.south_offset}')
+ return
+
+
+def map_tile_info(Z, X, Y):
+ N = 2.0 ** Z
+ lon_min = math.pi*(2*X-N)/N
+ lon_max = math.pi*(2*X+2-N)/N
+ lat_min = gd(math.pi*(N-2*Y-2)/N)
+ lat_max = gd(math.pi*(N-2*Y)/N)
+ r = 6371000
+ height = r*(lat_max-lat_min)
+ rdel_lon = r*(lon_max-lon_min)
+ width_n = rdel_lon*math.cos(lat_max)
+ width_s = rdel_lon*math.cos(lat_min)
+ area = r*rdel_lon*(math.sin(lat_max)-math.sin(lat_min))
+ print(f'(Z,X,Y) = ({Z},{X},{Y})')
+ print(f'west = {math.degrees(lon_min)}')
+ print(f'east = {math.degrees(lon_max)}')
+ print(f'south = {math.degrees(lat_min)}')
+ print(f'north = {math.degrees(lat_max)}')
+ print(f'height = {height/1000}')
+ print(f'width(N)= {width_n/1000}')
+ print(f'width(S)= {width_s/1000}')
+ print(f'area = {area/1000000}')
+ return
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description='Compute a full map description and download map tiles')
+
+ parser.add_argument('type', type=str, help='type of map computation',
+ choices=['boundaries', 'reference', 'areafit'])
+
+ parser.add_argument('-z', '--zoom', type=int, default=9,
+ help='zoom level (boundaries/reference)')
+ parser.add_argument('-w', '--west', type=float, default=11,
+ help='longitude west (boundaries/areafit)')
+ parser.add_argument('-e', '--east', type=float, default=13,
+ help='longitude east (boundaries/areafit)')
+ parser.add_argument('-n', '--north', type=float, default=48,
+ help='latitude north (boundaries/areafit)')
+ parser.add_argument('-s', '--south', type=float, default=50,
+ help='latitude south (boundaries/areafit)')
+ parser.add_argument('-lon', '--longitude', type=float, default=12,
+ help='longitude (reference)')
+ parser.add_argument('-lat', '--latitude', type=float, default=49,
+ help='latitude (reference)')
+ parser.add_argument('-mw', '--width', type=float, default=4,
+ help='map width as multiplicity of map tiles (reference/areafit)')
+ parser.add_argument('-mh', '--height', type=float, default=4,
+ help='map height as multiplicity of map tiles (reference/areafit)')
+ parser.add_argument('-a', '--align', type=str, default='center',
+ help='alignment of reference or area (reference/areafit)',
+ choices=['northwest', 'north', 'northeast',
+ 'west', 'center', 'east',
+ 'southwest', 'south', 'southeast'] )
+ parser.add_argument('-d', '--definition', type=str, default='mapdefinition',
+ help='name of the produced map definition for LaTeX')
+ parser.add_argument('-t', '--target', type=str, default='tiles',
+ help='target to create tiles or a merged map',
+ choices=['none', 'tiles', 'mergedmap', 'wmsmap'] )
+ parser.add_argument('-u', '--url', type=str, default=None,
+ help='url format with placeholder {z}{x}{y} for downloading tiles')
+ parser.add_argument('-at', '--attribution', type=str, default=None,
+ help='attribution text of the tile producer')
+ parser.add_argument('-atp', '--attributionprint', type=str, default=None,
+ help='attribution text of the tile producer')
+ parser.add_argument('-f', '--fileprefix', type=str, default='tiles/unknown',
+ help='prefix for local tile files, e.g. "tiles/map" for "tiles/map_10_10_10.png"')
+ parser.add_argument('-c', '--confirm', action="store_true",
+ help='confirm bulk download for map tiles')
+ parser.add_argument('-p', '--pixel', type=int, default=256,
+ help='pixel width/height of a tile')
+ parser.add_argument('-ts', '--tilesize', type=str, default=None,
+ help='TeX tile size')
+
+ args = parser.parse_args()
+
+ print('')
+ print('** This is maptiles.py version', packageversion,
+ 'for generating', args.definition)
+
+ switcher = {
+ 'northwest': (-1,-1),
+ 'north': ( 0,-1),
+ 'northeast': ( 1,-1),
+ 'west': (-1, 0),
+ 'center': ( 0, 0),
+ 'east': ( 1, 0),
+ 'southwest': (-1, 1),
+ 'south': ( 0, 1),
+ 'southeast': ( 1, 1)
+ }
+ (args.xalign, args.yalign) = switcher.get(args.align)
+
+ switcher = {
+ 'boundaries': MapDefinition.construct_from_boundaries_args,
+ 'reference': MapDefinition.construct_from_reference_args,
+ 'areafit': MapDefinition.construct_to_fit_region_args
+ }
+ mapdef = switcher.get(args.type)(args)
+
+ switcher = {
+ 'none': 0,
+ 'tiles': 1,
+ 'mergedmap': 2,
+ 'wmsmap': 3
+ }
+ target = switcher.get(args.target)
+
+ tiles_success = False
+ merge_success = False
+ wms_success = False
+
+ if target>0:
+ if args.url!=None:
+ if target<3:
+ if mapdef.get_tile_quantity()>400:
+ if args.confirm:
+ tiles_success = mapdef.download_tiles(args.url, args.fileprefix)
+ else:
+ print(f'Too many tiles ({mapdef.get_tile_quantity()}). Add confirm option to proceed anyway.');
+ else:
+ tiles_success = mapdef.download_tiles(args.url, args.fileprefix)
+ if tiles_success:
+ print('** Download of tiles successful for', args.definition)
+ if target>1:
+ merge_success = mapdef.merge_map(args.definition, args.fileprefix)
+ if merge_success:
+ print('** Merging tiles successful for', args.definition)
+ else:
+ print('** WARNING: Merging tiles failed for', args.definition)
+ else:
+ print('** WARNING: Map tiles download failed for', args.definition)
+ else:
+ if mapdef.get_pixel_quantity()>100000000:
+ if args.confirm:
+ wms_success = mapdef.download_wms_map(args.url, args.definition)
+ else:
+ print(f'Too many pixels ({mapdef.get_pixel_quantity()}). Add confirm option to proceed anyway.');
+ else:
+ wms_success = mapdef.download_wms_map(args.url, args.definition)
+ else:
+ print('No url for download given')
+
+ mapdef.save_map(args.definition, tiles_success, merge_success, wms_success)
+\end{filecontents*}
+
diff --git a/Master/texmf-dist/tex/latex/mercatormap/mercatorsupplier.def b/Master/texmf-dist/tex/latex/mercatormap/mercatorsupplier.def
new file mode 100644
index 00000000000..438374ba26f
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/mercatormap/mercatorsupplier.def
@@ -0,0 +1,290 @@
+%% The LaTeX package mercatormap - version 1.00 (2020/04/20)
+%% mercatorsupplier.def: predefined map supplier list
+%%
+%% -------------------------------------------------------------------------------------------
+%% Copyright (c) 2020 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
+%%
+
+\NewDocumentCommand\mrcumlaut{m}{\"{#1}}
+
+\cs_new:Npn \__mermap_new_supply_source:nn #1#2
+ {
+ \keys_define:nn { mermap/supply/_source }
+ {
+ #1 .meta:nn = {mermap/supply}{#2}
+ }
+ }
+
+\NewDocumentCommand\mrcnewsupplysource {mm} {
+ \__mermap_new_supply_source:nn {#1}{#2}
+}
+
+\__mermap_new_supply_source:nn { dummy }
+ {
+ url = http://127.0.0.1/dummy/{z}/{x}/{y}.png,
+ attribution = {Dummy~tile~server},
+ attribution~print = {Dummy~tile~server},
+ basename = tiles/dummy,
+ }
+
+\__mermap_new_supply_source:nn { opentopomap }
+ {
+ url = https://tile.opentopomap.org/{z}/{x}/{y}.png,
+ attribution = {
+ Kartendaten:~\textcopyright\nobreakspace\href{https://openstreetmap.org/copyright}{OpenStreetMap}
+ \ Mitwirkende,~SRTM\nobreakspace\textbar\nobreakspace
+ Kartendarstellung:~\textcopyright\nobreakspace\href{http://opentopomap.org/}{OpenTopoMap}
+ \ (\href{https://creativecommons.org/licenses/by-sa/3.0/}{CC-BY-SA})
+ },
+ attribution~print = {
+ Kartendaten:~\textcopyright\nobreakspace www.openstreetmap.org/copyright,
+ \ SRTM\nobreakspace\textbar\nobreakspace
+ Kartendarstellung:~\textcopyright\nobreakspace opentopomap.org~(CC-BY-SA)
+ },
+ basename = tiles/opentopomap,
+ }
+
+\keys_define:nn { mermap/supply }
+ {
+ __attribution_topplusopen .meta:nn = {mermap/supply} {
+ attribution = {
+ \textcopyright\nobreakspace\href{http://www.bkg.bund.de}{Bundesamt~f\mrcumlaut{u}r~Kartographie~und~Geod\mrcumlaut{a}sie}\nobreakspace\the\year,
+ \ \href{http://sg.geodatenzentrum.de/web_public/Datenquellen_TopPlus_Open.pdf}{Datenquellen}
+ },
+ attribution~print = {
+ \textcopyright\nobreakspace Bundesamt~f\mrcumlaut{u}r~Kartographie~und~Geod\mrcumlaut{a}sie\nobreakspace\the\year,
+ \ Datenquellen:~\detokenize{http://sg.geodatenzentrum.de/web_public/Datenquellen_TopPlus_Open.pdf}
+ }
+ }
+ }
+
+\__mermap_new_supply_source:nn { topplusopen~web }
+ {
+ url = {https://sgx.geodatenzentrum.de/wmts_topplus_open/tile/1.0.0/web/default/WEBMERCATOR/{z}/{y}/{x}.png},
+ __attribution_topplusopen,
+ basename = tiles/tpo_web,
+ }
+
+\__mermap_new_supply_source:nn { topplusopen~web~grau }
+ {
+ url = {https://sgx.geodatenzentrum.de/wmts_topplus_open/tile/1.0.0/web_grau/default/WEBMERCATOR/{z}/{y}/{x}.png},
+ __attribution_topplusopen,
+ basename = tiles/tpo_web_grau,
+ }
+
+\cs_new:Npn \__mermap_new_supply_source_topplusopen:n #1
+ {
+ \keys_define:nn { mermap/supply/_source }
+ {
+ topplusopen~#1 .meta:nn = {mermap/supply}{
+ url = {https://sgx.geodatenzentrum.de/wms_topplus_open?service=wms&version=1.3.0&request=GetMap&Layers=#1&STYLES=default&CRS=EPSG:3857&bbox={xmin},{ymin},{xmax},{ymax}&width={width}&height={height}&Format=image/png},
+ __attribution_topplusopen,
+ basename = tiles/tpo,
+ },
+ topplusopen~#1~grau .meta:nn = {mermap/supply}{
+ url = {https://sgx.geodatenzentrum.de/wms_topplus_open?service=wms&version=1.3.0&request=GetMap&Layers=#1_grau&STYLES=default&CRS=EPSG:3857&bbox={xmin},{ymin},{xmax},{ymax}&width={width}&height={height}&Format=image/png},
+ __attribution_topplusopen,
+ basename = tiles/tpo,
+ },
+ }
+ }
+\__mermap_new_supply_source_topplusopen:n { p5 }
+\__mermap_new_supply_source_topplusopen:n { p10 }
+\__mermap_new_supply_source_topplusopen:n { p17.5 }
+\__mermap_new_supply_source_topplusopen:n { p25 }
+\__mermap_new_supply_source_topplusopen:n { p50 }
+\__mermap_new_supply_source_topplusopen:n { p100 }
+\__mermap_new_supply_source_topplusopen:n { p250 }
+
+\__mermap_new_supply_source:nn { openrouteservice~mapsurfer }
+ {
+ url~with~api~key = {https://api.openrouteservice.org/mapsurfer/{z}/{x}/{y}.png?api_key=}{openrouteservice}{},
+ attribution = {
+ Service~\textcopyright\nobreakspace\href{https://openrouteservice.org/}{openrouteservice.org}
+ \nobreakspace\textbar\nobreakspace
+ Map~data~\textcopyright\nobreakspace\href{https://openstreetmap.org/copyright}{OpenStreetMap}~contributors
+ },
+ attribution~print = {
+ Service~\textcopyright\nobreakspace openrouteservice.org
+ \nobreakspace\textbar\nobreakspace
+ Map~data~\textcopyright\nobreakspace OpenStreetMap~contributors
+ },
+ basename = tiles/mapsurfer,
+ }
+
+\keys_define:nn { mermap/supply }
+ {
+ __attribution_stamen .meta:nn = {mermap/supply} {
+ attribution = {
+ Map~tiles~by~\href{http://stamen.com}{Stamen~Design},
+ \ under~\href{http://creativecommons.org/licenses/by/3.0}{CC~BY~3.0}.
+ \ Data~by~\href{http://openstreetmap.org}{OpenStreetMap},
+ \ under~\href{http://www.openstreetmap.org/copyright}{ODbL}.
+ },
+ attribution~print = {
+ Map~tiles~by~Stamen~Design~(stamen.com),
+ \ under~CC~BY~3.0.
+ \ Data~by~OpenStreetMap,
+ \ under~ODbl~(www.openstreetmap.org/copyright).
+ }
+ }
+ }
+\__mermap_new_supply_source:nn { stamen~terrain }
+ {
+ url = {https://stamen-tiles-a.a.ssl.fastly.net/terrain/{z}/{x}/{y}.png},
+ __attribution_stamen,
+ basename = tiles/terrain,
+ }
+\__mermap_new_supply_source:nn { stamen~terrain-background }
+ {
+ url = {https://stamen-tiles-a.a.ssl.fastly.net/terrain-background/{z}/{x}/{y}.png},
+ __attribution_stamen,
+ basename = tiles/terrain-background,
+ }
+\__mermap_new_supply_source:nn { stamen~terrain-labels }
+ {
+ url = {https://stamen-tiles-a.a.ssl.fastly.net/terrain-labels/{z}/{x}/{y}.png},
+ __attribution_stamen,
+ basename = tiles/terrain-labels,
+ }
+\__mermap_new_supply_source:nn { stamen~terrain-lines }
+ {
+ url = {https://stamen-tiles-a.a.ssl.fastly.net/terrain-lines/{z}/{x}/{y}.png},
+ __attribution_stamen,
+ basename = tiles/terrain-lines,
+ }
+\__mermap_new_supply_source:nn { stamen~toner }
+ {
+ url = {https://stamen-tiles-a.a.ssl.fastly.net/toner/{z}/{x}/{y}.png},
+ __attribution_stamen,
+ basename = tiles/toner,
+ }
+\__mermap_new_supply_source:nn { stamen~toner-lite }
+ {
+ url = {https://stamen-tiles-a.a.ssl.fastly.net/toner-lite/{z}/{x}/{y}.png},
+ __attribution_stamen,
+ basename = tiles/toner-lite,
+ }
+\__mermap_new_supply_source:nn { stamen~toner-hybrid }
+ {
+ url = {https://stamen-tiles-a.a.ssl.fastly.net/toner-hybrid/{z}/{x}/{y}.png},
+ __attribution_stamen,
+ basename = tiles/toner-hybrid,
+ }
+\__mermap_new_supply_source:nn { stamen~toner-background }
+ {
+ url = {https://stamen-tiles-a.a.ssl.fastly.net/toner-background/{z}/{x}/{y}.png},
+ __attribution_stamen,
+ basename = tiles/toner-background,
+ }
+\__mermap_new_supply_source:nn { stamen~toner-labels }
+ {
+ url = {https://stamen-tiles-a.a.ssl.fastly.net/toner-labels/{z}/{x}/{y}.png},
+ __attribution_stamen,
+ basename = tiles/toner-labels,
+ }
+\__mermap_new_supply_source:nn { stamen~toner-lines }
+ {
+ url = {https://stamen-tiles-a.a.ssl.fastly.net/toner-lines/{z}/{x}/{y}.png},
+ __attribution_stamen,
+ basename = tiles/toner-lines,
+ }
+\__mermap_new_supply_source:nn { stamen~watercolor }
+ {
+ url = {https://stamen-tiles-a.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.png},
+ attribution = {
+ Map~tiles~by~\href{http://stamen.com}{Stamen~Design},
+ \ under~\href{http://creativecommons.org/licenses/by/3.0}{CC~BY~3.0}.
+ \ Data~by~\href{http://openstreetmap.org}{OpenStreetMap},
+ \ under~\href{http://creativecommons.org/licenses/by-sa/3.0}{CC~BY~SA}.
+ },
+ attribution~print = {
+ Map~tiles~by~Stamen~Design~(stamen.com),
+ \ under~CC~BY~3.0.
+ \ Data~by~OpenStreetMap,
+ \ under~CC~BY~SA.
+ },
+ basename = tiles/watercolor,
+ }
+
+\keys_define:nn { mermap/supply }
+ {
+ __attribution_thunderforest .meta:nn = {mermap/supply} {
+ attribution = {
+ Maps~\textcopyright\nobreakspace\href{https://www.thunderforest.com/}{Thunderforest},
+ \ Data~\textcopyright\nobreakspace\href{https://openstreetmap.org/copyright}{OpenStreetMap~contributors}
+ },
+ attribution~print = {
+ Maps~\textcopyright\nobreakspace www.thunderforest.com,
+ \ Data~\textcopyright\nobreakspace www.osm.org/copyright
+ }
+ }
+ }
+\__mermap_new_supply_source:nn { thunderforest~opencyclemap }
+ {
+ url~with~api~key = {https://tile.thunderforest.com/cycle/{z}/{x}/{y}.png?apikey=}{thunderforest}{},
+ __attribution_thunderforest,
+ basename = tiles/opencyclemap,
+ }
+\__mermap_new_supply_source:nn { thunderforest~transport }
+ {
+ url~with~api~key = {https://tile.thunderforest.com/transport/{z}/{x}/{y}.png?apikey=}{thunderforest}{},
+ __attribution_thunderforest,
+ basename = tiles/transport,
+ }
+\__mermap_new_supply_source:nn { thunderforest~landscape }
+ {
+ url~with~api~key = {https://tile.thunderforest.com/landscape/{z}/{x}/{y}.png?apikey=}{thunderforest}{},
+ __attribution_thunderforest,
+ basename = tiles/landscape,
+ }
+\__mermap_new_supply_source:nn { thunderforest~outdoors }
+ {
+ url~with~api~key = {https://tile.thunderforest.com/outdoors/{z}/{x}/{y}.png?apikey=}{thunderforest}{},
+ __attribution_thunderforest,
+ basename = tiles/outdoors,
+ }
+\__mermap_new_supply_source:nn { thunderforest~transport-dark }
+ {
+ url~with~api~key = {https://tile.thunderforest.com/transport-dark/{z}/{x}/{y}.png?apikey=}{thunderforest}{},
+ __attribution_thunderforest,
+ basename = tiles/transport-dark,
+ }
+\__mermap_new_supply_source:nn { thunderforest~spinal-map }
+ {
+ url~with~api~key = {https://tile.thunderforest.com/spinal-map/{z}/{x}/{y}.png?apikey=}{thunderforest}{},
+ __attribution_thunderforest,
+ basename = tiles/spinal-map,
+ }
+\__mermap_new_supply_source:nn { thunderforest~pioneer }
+ {
+ url~with~api~key = {https://tile.thunderforest.com/pioneer/{z}/{x}/{y}.png?apikey=}{thunderforest}{},
+ __attribution_thunderforest,
+ basename = tiles/pioneer,
+ }
+\__mermap_new_supply_source:nn { thunderforest~mobile-atlas }
+ {
+ url~with~api~key = {https://tile.thunderforest.com/mobile-atlas/{z}/{x}/{y}.png?apikey=}{thunderforest}{},
+ __attribution_thunderforest,
+ basename = tiles/mobile-atlas,
+ }
+\__mermap_new_supply_source:nn { thunderforest~neighbourhood }
+ {
+ url~with~api~key = {https://tile.thunderforest.com/neighbourhood/{z}/{x}/{y}.png?apikey=}{thunderforest}{},
+ __attribution_thunderforest,
+ basename = tiles/neighbourhood,
+ }
+