MapProxy 1.16.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (458) hide show
  1. mapproxy/__init__.py +0 -0
  2. mapproxy/cache/__init__.py +36 -0
  3. mapproxy/cache/azureblob.py +145 -0
  4. mapproxy/cache/base.py +111 -0
  5. mapproxy/cache/compact.py +664 -0
  6. mapproxy/cache/couchdb.py +295 -0
  7. mapproxy/cache/dummy.py +34 -0
  8. mapproxy/cache/file.py +185 -0
  9. mapproxy/cache/geopackage.py +609 -0
  10. mapproxy/cache/legend.py +83 -0
  11. mapproxy/cache/mbtiles.py +392 -0
  12. mapproxy/cache/meta.py +78 -0
  13. mapproxy/cache/path.py +250 -0
  14. mapproxy/cache/redis.py +88 -0
  15. mapproxy/cache/renderd.py +95 -0
  16. mapproxy/cache/riak.py +202 -0
  17. mapproxy/cache/s3.py +177 -0
  18. mapproxy/cache/tile.py +699 -0
  19. mapproxy/client/__init__.py +0 -0
  20. mapproxy/client/arcgis.py +79 -0
  21. mapproxy/client/cgi.py +139 -0
  22. mapproxy/client/http.py +315 -0
  23. mapproxy/client/log.py +33 -0
  24. mapproxy/client/tile.py +150 -0
  25. mapproxy/client/wms.py +254 -0
  26. mapproxy/compat/__init__.py +46 -0
  27. mapproxy/compat/image.py +79 -0
  28. mapproxy/compat/itertools.py +29 -0
  29. mapproxy/compat/modules.py +13 -0
  30. mapproxy/config/__init__.py +22 -0
  31. mapproxy/config/config.py +201 -0
  32. mapproxy/config/coverage.py +107 -0
  33. mapproxy/config/defaults.py +98 -0
  34. mapproxy/config/loader.py +2286 -0
  35. mapproxy/config/spec.py +644 -0
  36. mapproxy/config/validator.py +239 -0
  37. mapproxy/config_template/__init__.py +0 -0
  38. mapproxy/config_template/base_config/config.wsgi +10 -0
  39. mapproxy/config_template/base_config/full_example.yaml +593 -0
  40. mapproxy/config_template/base_config/full_seed_example.yaml +79 -0
  41. mapproxy/config_template/base_config/log.ini +35 -0
  42. mapproxy/config_template/base_config/mapproxy.yaml +60 -0
  43. mapproxy/config_template/base_config/seed.yaml +27 -0
  44. mapproxy/exception.py +142 -0
  45. mapproxy/featureinfo.py +252 -0
  46. mapproxy/grid.py +1170 -0
  47. mapproxy/image/__init__.py +536 -0
  48. mapproxy/image/fonts/DejaVuSans.ttf +0 -0
  49. mapproxy/image/fonts/DejaVuSansMono.ttf +0 -0
  50. mapproxy/image/fonts/LICENSE +99 -0
  51. mapproxy/image/fonts/__init__.py +0 -0
  52. mapproxy/image/mask.py +75 -0
  53. mapproxy/image/merge.py +316 -0
  54. mapproxy/image/message.py +347 -0
  55. mapproxy/image/opts.py +182 -0
  56. mapproxy/image/tile.py +167 -0
  57. mapproxy/image/transform.py +350 -0
  58. mapproxy/layer.py +470 -0
  59. mapproxy/multiapp.py +231 -0
  60. mapproxy/proj.py +302 -0
  61. mapproxy/request/__init__.py +18 -0
  62. mapproxy/request/arcgis.py +259 -0
  63. mapproxy/request/base.py +476 -0
  64. mapproxy/request/tile.py +128 -0
  65. mapproxy/request/wms/__init__.py +793 -0
  66. mapproxy/request/wms/exception.py +99 -0
  67. mapproxy/request/wmts.py +436 -0
  68. mapproxy/response.py +237 -0
  69. mapproxy/script/__init__.py +0 -0
  70. mapproxy/script/conf/__init__.py +0 -0
  71. mapproxy/script/conf/app.py +195 -0
  72. mapproxy/script/conf/caches.py +45 -0
  73. mapproxy/script/conf/layers.py +54 -0
  74. mapproxy/script/conf/seeds.py +37 -0
  75. mapproxy/script/conf/sources.py +86 -0
  76. mapproxy/script/conf/utils.py +143 -0
  77. mapproxy/script/defrag.py +184 -0
  78. mapproxy/script/export.py +333 -0
  79. mapproxy/script/grids.py +188 -0
  80. mapproxy/script/scales.py +126 -0
  81. mapproxy/script/util.py +406 -0
  82. mapproxy/script/wms_capabilities.py +152 -0
  83. mapproxy/seed/__init__.py +0 -0
  84. mapproxy/seed/cachelock.py +121 -0
  85. mapproxy/seed/cleanup.py +187 -0
  86. mapproxy/seed/config.py +469 -0
  87. mapproxy/seed/script.py +388 -0
  88. mapproxy/seed/seeder.py +538 -0
  89. mapproxy/seed/spec.py +64 -0
  90. mapproxy/seed/util.py +254 -0
  91. mapproxy/service/__init__.py +14 -0
  92. mapproxy/service/base.py +46 -0
  93. mapproxy/service/demo.py +356 -0
  94. mapproxy/service/kml.py +331 -0
  95. mapproxy/service/ows.py +38 -0
  96. mapproxy/service/template_helper.py +53 -0
  97. mapproxy/service/templates/demo/capabilities_demo.html +16 -0
  98. mapproxy/service/templates/demo/demo.html +181 -0
  99. mapproxy/service/templates/demo/openlayers-demo.cfg +16 -0
  100. mapproxy/service/templates/demo/static/img/blank.gif +0 -0
  101. mapproxy/service/templates/demo/static/img/east-mini.png +0 -0
  102. mapproxy/service/templates/demo/static/img/north-mini.png +0 -0
  103. mapproxy/service/templates/demo/static/img/south-mini.png +0 -0
  104. mapproxy/service/templates/demo/static/img/west-mini.png +0 -0
  105. mapproxy/service/templates/demo/static/img/zoom-minus-mini.png +0 -0
  106. mapproxy/service/templates/demo/static/img/zoom-plus-mini.png +0 -0
  107. mapproxy/service/templates/demo/static/img/zoom-world-mini.png +0 -0
  108. mapproxy/service/templates/demo/static/logo.png +0 -0
  109. mapproxy/service/templates/demo/static/ol.css +345 -0
  110. mapproxy/service/templates/demo/static/ol.js +4 -0
  111. mapproxy/service/templates/demo/static/proj4.min.js +1 -0
  112. mapproxy/service/templates/demo/static/proj4defs.js +1 -0
  113. mapproxy/service/templates/demo/static/site.css +137 -0
  114. mapproxy/service/templates/demo/static/theme/default/framedCloud.css +0 -0
  115. mapproxy/service/templates/demo/static/theme/default/google.css +17 -0
  116. mapproxy/service/templates/demo/static/theme/default/ie6-style.css +10 -0
  117. mapproxy/service/templates/demo/static/theme/default/style.css +482 -0
  118. mapproxy/service/templates/demo/static.html +34 -0
  119. mapproxy/service/templates/demo/tms_demo.html +103 -0
  120. mapproxy/service/templates/demo/wms_demo.html +140 -0
  121. mapproxy/service/templates/demo/wmts_demo.html +110 -0
  122. mapproxy/service/templates/tms_capabilities.xml +13 -0
  123. mapproxy/service/templates/tms_exception.xml +4 -0
  124. mapproxy/service/templates/tms_root_resource.xml +7 -0
  125. mapproxy/service/templates/tms_tilemap_capabilities.xml +14 -0
  126. mapproxy/service/templates/wms100capabilities.xml +112 -0
  127. mapproxy/service/templates/wms100exception.xml +4 -0
  128. mapproxy/service/templates/wms110capabilities.xml +152 -0
  129. mapproxy/service/templates/wms110exception.xml +5 -0
  130. mapproxy/service/templates/wms111capabilities.xml +183 -0
  131. mapproxy/service/templates/wms111exception.xml +5 -0
  132. mapproxy/service/templates/wms130capabilities.xml +326 -0
  133. mapproxy/service/templates/wms130exception.xml +8 -0
  134. mapproxy/service/templates/wmts100capabilities.xml +155 -0
  135. mapproxy/service/templates/wmts100exception.xml +9 -0
  136. mapproxy/service/tile.py +536 -0
  137. mapproxy/service/wms.py +851 -0
  138. mapproxy/service/wmts.py +381 -0
  139. mapproxy/source/__init__.py +75 -0
  140. mapproxy/source/arcgis.py +39 -0
  141. mapproxy/source/error.py +39 -0
  142. mapproxy/source/mapnik.py +259 -0
  143. mapproxy/source/tile.py +96 -0
  144. mapproxy/source/wms.py +270 -0
  145. mapproxy/srs.py +726 -0
  146. mapproxy/template.py +54 -0
  147. mapproxy/test/__init__.py +0 -0
  148. mapproxy/test/conftest.py +7 -0
  149. mapproxy/test/helper.py +247 -0
  150. mapproxy/test/http.py +494 -0
  151. mapproxy/test/image.py +210 -0
  152. mapproxy/test/mocker.py +2268 -0
  153. mapproxy/test/schemas/inspire/common/1.0/common.xsd +1461 -0
  154. mapproxy/test/schemas/inspire/common/1.0/enums/enum_bul.xsd +108 -0
  155. mapproxy/test/schemas/inspire/common/1.0/enums/enum_cze.xsd +108 -0
  156. mapproxy/test/schemas/inspire/common/1.0/enums/enum_dan.xsd +108 -0
  157. mapproxy/test/schemas/inspire/common/1.0/enums/enum_dut.xsd +108 -0
  158. mapproxy/test/schemas/inspire/common/1.0/enums/enum_eng.xsd +155 -0
  159. mapproxy/test/schemas/inspire/common/1.0/enums/enum_est.xsd +108 -0
  160. mapproxy/test/schemas/inspire/common/1.0/enums/enum_fin.xsd +108 -0
  161. mapproxy/test/schemas/inspire/common/1.0/enums/enum_fre.xsd +108 -0
  162. mapproxy/test/schemas/inspire/common/1.0/enums/enum_ger.xsd +108 -0
  163. mapproxy/test/schemas/inspire/common/1.0/enums/enum_gle.xsd +109 -0
  164. mapproxy/test/schemas/inspire/common/1.0/enums/enum_gre.xsd +108 -0
  165. mapproxy/test/schemas/inspire/common/1.0/enums/enum_hun.xsd +108 -0
  166. mapproxy/test/schemas/inspire/common/1.0/enums/enum_ita.xsd +108 -0
  167. mapproxy/test/schemas/inspire/common/1.0/enums/enum_lav.xsd +108 -0
  168. mapproxy/test/schemas/inspire/common/1.0/enums/enum_lit.xsd +108 -0
  169. mapproxy/test/schemas/inspire/common/1.0/enums/enum_mlt.xsd +108 -0
  170. mapproxy/test/schemas/inspire/common/1.0/enums/enum_pol.xsd +108 -0
  171. mapproxy/test/schemas/inspire/common/1.0/enums/enum_por.xsd +108 -0
  172. mapproxy/test/schemas/inspire/common/1.0/enums/enum_rum.xsd +108 -0
  173. mapproxy/test/schemas/inspire/common/1.0/enums/enum_slo.xsd +108 -0
  174. mapproxy/test/schemas/inspire/common/1.0/enums/enum_slv.xsd +108 -0
  175. mapproxy/test/schemas/inspire/common/1.0/enums/enum_spa.xsd +108 -0
  176. mapproxy/test/schemas/inspire/common/1.0/enums/enum_swe.xsd +108 -0
  177. mapproxy/test/schemas/inspire/common/1.0/network.xsd +521 -0
  178. mapproxy/test/schemas/inspire/inspire_vs/1.0/inspire_vs.xsd +19 -0
  179. mapproxy/test/schemas/kml/2.2.0/ReadMe.txt +14 -0
  180. mapproxy/test/schemas/kml/2.2.0/atom-author-link.xsd +66 -0
  181. mapproxy/test/schemas/kml/2.2.0/ogckml22.xsd +1646 -0
  182. mapproxy/test/schemas/kml/2.2.0/xAL.xsd +1680 -0
  183. mapproxy/test/schemas/ows/1.1.0/ReadMe.txt +87 -0
  184. mapproxy/test/schemas/ows/1.1.0/ows19115subset.xsd +235 -0
  185. mapproxy/test/schemas/ows/1.1.0/owsAll.xsd +23 -0
  186. mapproxy/test/schemas/ows/1.1.0/owsCommon.xsd +157 -0
  187. mapproxy/test/schemas/ows/1.1.0/owsContents.xsd +86 -0
  188. mapproxy/test/schemas/ows/1.1.0/owsDataIdentification.xsd +127 -0
  189. mapproxy/test/schemas/ows/1.1.0/owsDomainType.xsd +279 -0
  190. mapproxy/test/schemas/ows/1.1.0/owsExceptionReport.xsd +76 -0
  191. mapproxy/test/schemas/ows/1.1.0/owsGetCapabilities.xsd +112 -0
  192. mapproxy/test/schemas/ows/1.1.0/owsGetResourceByID.xsd +51 -0
  193. mapproxy/test/schemas/ows/1.1.0/owsInputOutputData.xsd +59 -0
  194. mapproxy/test/schemas/ows/1.1.0/owsManifest.xsd +125 -0
  195. mapproxy/test/schemas/ows/1.1.0/owsOperationsMetadata.xsd +140 -0
  196. mapproxy/test/schemas/ows/1.1.0/owsServiceIdentification.xsd +60 -0
  197. mapproxy/test/schemas/ows/1.1.0/owsServiceProvider.xsd +47 -0
  198. mapproxy/test/schemas/sld/1.1.0/sld_capabilities.xsd +27 -0
  199. mapproxy/test/schemas/wms/1.0.0/capabilities_1_0_0.dtd +353 -0
  200. mapproxy/test/schemas/wms/1.0.0/capabilities_1_0_0.xml +188 -0
  201. mapproxy/test/schemas/wms/1.0.7/capabilities_1_0_7.dtd +524 -0
  202. mapproxy/test/schemas/wms/1.0.7/capabilities_1_0_7.xml +260 -0
  203. mapproxy/test/schemas/wms/1.1.0/capabilities_1_1_0.dtd +273 -0
  204. mapproxy/test/schemas/wms/1.1.0/capabilities_1_1_0.xml +303 -0
  205. mapproxy/test/schemas/wms/1.1.0/exception_1_1_0.dtd +6 -0
  206. mapproxy/test/schemas/wms/1.1.0/exception_1_1_0.xml +33 -0
  207. mapproxy/test/schemas/wms/1.1.1/OGC-exception.xsd +68 -0
  208. mapproxy/test/schemas/wms/1.1.1/WMS_DescribeLayerResponse.dtd +22 -0
  209. mapproxy/test/schemas/wms/1.1.1/WMS_MS_Capabilities.dtd +274 -0
  210. mapproxy/test/schemas/wms/1.1.1/WMS_exception_1_1_1.dtd +5 -0
  211. mapproxy/test/schemas/wms/1.1.1/capabilities_1_1_1.dtd +276 -0
  212. mapproxy/test/schemas/wms/1.1.1/capabilities_1_1_1.xml +303 -0
  213. mapproxy/test/schemas/wms/1.1.1/exception_1_1_1.dtd +6 -0
  214. mapproxy/test/schemas/wms/1.1.1/exception_1_1_1.xml +33 -0
  215. mapproxy/test/schemas/wms/1.3.0/ReadMe.txt +8 -0
  216. mapproxy/test/schemas/wms/1.3.0/capabilities_1_3_0.xml +277 -0
  217. mapproxy/test/schemas/wms/1.3.0/capabilities_1_3_0.xsd +611 -0
  218. mapproxy/test/schemas/wms/1.3.0/exceptions_1_3_0.xml +34 -0
  219. mapproxy/test/schemas/wms/1.3.0/exceptions_1_3_0.xsd +28 -0
  220. mapproxy/test/schemas/wmsc/1.1.1/OGC-exception.xsd +68 -0
  221. mapproxy/test/schemas/wmsc/1.1.1/WMS_DescribeLayerResponse.dtd +22 -0
  222. mapproxy/test/schemas/wmsc/1.1.1/WMS_MS_Capabilities.dtd +283 -0
  223. mapproxy/test/schemas/wmsc/1.1.1/WMS_exception_1_1_1.dtd +5 -0
  224. mapproxy/test/schemas/wmsc/1.1.1/capabilities_1_1_1.dtd +276 -0
  225. mapproxy/test/schemas/wmsc/1.1.1/capabilities_1_1_1.xml +303 -0
  226. mapproxy/test/schemas/wmsc/1.1.1/exception_1_1_1.dtd +6 -0
  227. mapproxy/test/schemas/wmsc/1.1.1/exception_1_1_1.xml +33 -0
  228. mapproxy/test/schemas/wmts/1.0/ReadMe.txt +32 -0
  229. mapproxy/test/schemas/wmts/1.0/wmts.xsd +28 -0
  230. mapproxy/test/schemas/wmts/1.0/wmtsAbstract.wsdl +151 -0
  231. mapproxy/test/schemas/wmts/1.0/wmtsGetCapabilities_request.xsd +38 -0
  232. mapproxy/test/schemas/wmts/1.0/wmtsGetCapabilities_response.xsd +564 -0
  233. mapproxy/test/schemas/wmts/1.0/wmtsGetFeatureInfo_request.xsd +57 -0
  234. mapproxy/test/schemas/wmts/1.0/wmtsGetFeatureInfo_response.xsd +72 -0
  235. mapproxy/test/schemas/wmts/1.0/wmtsGetTile_request.xsd +91 -0
  236. mapproxy/test/schemas/wmts/1.0/wmtsKVP.xsd +76 -0
  237. mapproxy/test/schemas/wmts/1.0/wmtsPayload_response.xsd +70 -0
  238. mapproxy/test/schemas/xlink/1.0.0/ReadMe.txt +6 -0
  239. mapproxy/test/schemas/xlink/1.0.0/xlinks.xsd +122 -0
  240. mapproxy/test/schemas/xml.xsd +287 -0
  241. mapproxy/test/system/__init__.py +98 -0
  242. mapproxy/test/system/fixture/arcgis.yaml +57 -0
  243. mapproxy/test/system/fixture/auth.yaml +70 -0
  244. mapproxy/test/system/fixture/cache.mbtiles +0 -0
  245. mapproxy/test/system/fixture/cache_azureblob.yaml +59 -0
  246. mapproxy/test/system/fixture/cache_band_merge.yaml +73 -0
  247. mapproxy/test/system/fixture/cache_bulk_meta_tiles.yaml +24 -0
  248. mapproxy/test/system/fixture/cache_data/dop_cache_EPSG3857/00/000/000/000/000/000/000.png +0 -0
  249. mapproxy/test/system/fixture/cache_data/wms_cache_EPSG900913/01/000/000/000/000/000/001.jpeg +0 -0
  250. mapproxy/test/system/fixture/cache_data/wms_cache_transparent_EPSG900913/01/000/000/000/000/000/001.png +0 -0
  251. mapproxy/test/system/fixture/cache_geopackage.yaml +56 -0
  252. mapproxy/test/system/fixture/cache_grid_names.yaml +50 -0
  253. mapproxy/test/system/fixture/cache_mbtiles.yaml +28 -0
  254. mapproxy/test/system/fixture/cache_s3.yaml +58 -0
  255. mapproxy/test/system/fixture/cache_source.yaml +81 -0
  256. mapproxy/test/system/fixture/combined_sources.yaml +130 -0
  257. mapproxy/test/system/fixture/coverage.yaml +77 -0
  258. mapproxy/test/system/fixture/demo.yaml +135 -0
  259. mapproxy/test/system/fixture/dimension.yaml +59 -0
  260. mapproxy/test/system/fixture/disable_storage.yaml +25 -0
  261. mapproxy/test/system/fixture/empty_ogrdata.geojson +1 -0
  262. mapproxy/test/system/fixture/formats.yaml +72 -0
  263. mapproxy/test/system/fixture/inspire.yaml +101 -0
  264. mapproxy/test/system/fixture/inspire_full.yaml +124 -0
  265. mapproxy/test/system/fixture/kml_layer.yaml +66 -0
  266. mapproxy/test/system/fixture/layer.yaml +260 -0
  267. mapproxy/test/system/fixture/layergroups.yaml +57 -0
  268. mapproxy/test/system/fixture/layergroups_root.yaml +106 -0
  269. mapproxy/test/system/fixture/legendgraphic.yaml +93 -0
  270. mapproxy/test/system/fixture/mapnik_source.yaml +66 -0
  271. mapproxy/test/system/fixture/mapproxy_export.yaml +12 -0
  272. mapproxy/test/system/fixture/mapserver.yaml +23 -0
  273. mapproxy/test/system/fixture/minimal_cgi.py +16 -0
  274. mapproxy/test/system/fixture/mixed_mode.yaml +49 -0
  275. mapproxy/test/system/fixture/multi_cache_layers.yaml +100 -0
  276. mapproxy/test/system/fixture/multiapp1.yaml +20 -0
  277. mapproxy/test/system/fixture/multiapp2.yaml +19 -0
  278. mapproxy/test/system/fixture/renderd_client.yaml +55 -0
  279. mapproxy/test/system/fixture/scalehints.yaml +70 -0
  280. mapproxy/test/system/fixture/seed.yaml +94 -0
  281. mapproxy/test/system/fixture/seed_mapproxy.yaml +39 -0
  282. mapproxy/test/system/fixture/seed_old.yaml +12 -0
  283. mapproxy/test/system/fixture/seed_timeouts.yaml +12 -0
  284. mapproxy/test/system/fixture/seed_timeouts_mapproxy.yaml +27 -0
  285. mapproxy/test/system/fixture/seedonly.yaml +51 -0
  286. mapproxy/test/system/fixture/sld.yaml +35 -0
  287. mapproxy/test/system/fixture/source_errors.yaml +84 -0
  288. mapproxy/test/system/fixture/source_errors_raise.yaml +82 -0
  289. mapproxy/test/system/fixture/tileservice_origin.yaml +26 -0
  290. mapproxy/test/system/fixture/tileservice_refresh.yaml +59 -0
  291. mapproxy/test/system/fixture/tilesource_minmax_res.yaml +22 -0
  292. mapproxy/test/system/fixture/util-conf-base-grids.yaml +5 -0
  293. mapproxy/test/system/fixture/util-conf-overwrite.yaml +13 -0
  294. mapproxy/test/system/fixture/util-conf-wms-111-cap.xml +90 -0
  295. mapproxy/test/system/fixture/util_grids.yaml +30 -0
  296. mapproxy/test/system/fixture/util_wms_capabilities111.xml +130 -0
  297. mapproxy/test/system/fixture/util_wms_capabilities130.xml +100 -0
  298. mapproxy/test/system/fixture/util_wms_capabilities_service_exception.xml +5 -0
  299. mapproxy/test/system/fixture/watermark.yaml +50 -0
  300. mapproxy/test/system/fixture/wms_srs_extent.yaml +39 -0
  301. mapproxy/test/system/fixture/wms_versions.yaml +38 -0
  302. mapproxy/test/system/fixture/wmts.yaml +134 -0
  303. mapproxy/test/system/fixture/wmts_dimensions.yaml +57 -0
  304. mapproxy/test/system/fixture/xslt_featureinfo.yaml +54 -0
  305. mapproxy/test/system/fixture/xslt_featureinfo_input.yaml +51 -0
  306. mapproxy/test/system/test_arcgis.py +156 -0
  307. mapproxy/test/system/test_auth.py +1134 -0
  308. mapproxy/test/system/test_behind_proxy.py +75 -0
  309. mapproxy/test/system/test_bulk_meta_tiles.py +106 -0
  310. mapproxy/test/system/test_cache_azureblob.py +127 -0
  311. mapproxy/test/system/test_cache_band_merge.py +103 -0
  312. mapproxy/test/system/test_cache_geopackage.py +144 -0
  313. mapproxy/test/system/test_cache_grid_names.py +89 -0
  314. mapproxy/test/system/test_cache_mbtiles.py +85 -0
  315. mapproxy/test/system/test_cache_s3.py +115 -0
  316. mapproxy/test/system/test_cache_source.py +146 -0
  317. mapproxy/test/system/test_combined_sources.py +335 -0
  318. mapproxy/test/system/test_coverage.py +140 -0
  319. mapproxy/test/system/test_decorate_img.py +214 -0
  320. mapproxy/test/system/test_demo.py +106 -0
  321. mapproxy/test/system/test_demo_with_extra_service.py +53 -0
  322. mapproxy/test/system/test_dimensions.py +278 -0
  323. mapproxy/test/system/test_disable_storage.py +42 -0
  324. mapproxy/test/system/test_formats.py +219 -0
  325. mapproxy/test/system/test_inspire_vs.py +173 -0
  326. mapproxy/test/system/test_kml.py +262 -0
  327. mapproxy/test/system/test_layergroups.py +160 -0
  328. mapproxy/test/system/test_legendgraphic.py +308 -0
  329. mapproxy/test/system/test_mapnik.py +161 -0
  330. mapproxy/test/system/test_mapserver.py +81 -0
  331. mapproxy/test/system/test_mixed_mode_format.py +195 -0
  332. mapproxy/test/system/test_multi_cache_layers.py +167 -0
  333. mapproxy/test/system/test_multiapp.py +92 -0
  334. mapproxy/test/system/test_refresh.py +207 -0
  335. mapproxy/test/system/test_renderd_client.py +304 -0
  336. mapproxy/test/system/test_response_headers.py +54 -0
  337. mapproxy/test/system/test_scalehints.py +140 -0
  338. mapproxy/test/system/test_seed.py +422 -0
  339. mapproxy/test/system/test_seed_only.py +93 -0
  340. mapproxy/test/system/test_sld.py +120 -0
  341. mapproxy/test/system/test_source_errors.py +377 -0
  342. mapproxy/test/system/test_tilesource_minmax_res.py +54 -0
  343. mapproxy/test/system/test_tms.py +276 -0
  344. mapproxy/test/system/test_tms_origin.py +46 -0
  345. mapproxy/test/system/test_util_conf.py +304 -0
  346. mapproxy/test/system/test_util_export.py +210 -0
  347. mapproxy/test/system/test_util_grids.py +88 -0
  348. mapproxy/test/system/test_util_wms_capabilities.py +182 -0
  349. mapproxy/test/system/test_watermark.py +91 -0
  350. mapproxy/test/system/test_wms.py +1611 -0
  351. mapproxy/test/system/test_wms_srs_extent.py +165 -0
  352. mapproxy/test/system/test_wms_version.py +85 -0
  353. mapproxy/test/system/test_wmsc.py +116 -0
  354. mapproxy/test/system/test_wmts.py +334 -0
  355. mapproxy/test/system/test_wmts_dimensions.py +206 -0
  356. mapproxy/test/system/test_wmts_restful.py +198 -0
  357. mapproxy/test/system/test_xslt_featureinfo.py +425 -0
  358. mapproxy/test/test_http_helper.py +219 -0
  359. mapproxy/test/unit/__init__.py +0 -0
  360. mapproxy/test/unit/epsg +2 -0
  361. mapproxy/test/unit/polygons/polygons.dbf +0 -0
  362. mapproxy/test/unit/polygons/polygons.shp +0 -0
  363. mapproxy/test/unit/polygons/polygons.shx +0 -0
  364. mapproxy/test/unit/test_async.py +245 -0
  365. mapproxy/test/unit/test_auth.py +419 -0
  366. mapproxy/test/unit/test_cache.py +1193 -0
  367. mapproxy/test/unit/test_cache_azureblob.py +94 -0
  368. mapproxy/test/unit/test_cache_compact.py +319 -0
  369. mapproxy/test/unit/test_cache_couchdb.py +114 -0
  370. mapproxy/test/unit/test_cache_geopackage.py +221 -0
  371. mapproxy/test/unit/test_cache_redis.py +67 -0
  372. mapproxy/test/unit/test_cache_riak.py +76 -0
  373. mapproxy/test/unit/test_cache_s3.py +84 -0
  374. mapproxy/test/unit/test_cache_tile.py +427 -0
  375. mapproxy/test/unit/test_client.py +479 -0
  376. mapproxy/test/unit/test_client_arcgis.py +73 -0
  377. mapproxy/test/unit/test_client_cgi.py +136 -0
  378. mapproxy/test/unit/test_collections.py +116 -0
  379. mapproxy/test/unit/test_concat_legends.py +37 -0
  380. mapproxy/test/unit/test_conf_loader.py +1061 -0
  381. mapproxy/test/unit/test_conf_validator.py +416 -0
  382. mapproxy/test/unit/test_config.py +117 -0
  383. mapproxy/test/unit/test_decorate_img.py +185 -0
  384. mapproxy/test/unit/test_exceptions.py +258 -0
  385. mapproxy/test/unit/test_featureinfo.py +291 -0
  386. mapproxy/test/unit/test_file_lock_load.py +49 -0
  387. mapproxy/test/unit/test_geom.py +503 -0
  388. mapproxy/test/unit/test_grid.py +1258 -0
  389. mapproxy/test/unit/test_image.py +1053 -0
  390. mapproxy/test/unit/test_image_mask.py +181 -0
  391. mapproxy/test/unit/test_image_messages.py +197 -0
  392. mapproxy/test/unit/test_image_options.py +160 -0
  393. mapproxy/test/unit/test_isodate.py +122 -0
  394. mapproxy/test/unit/test_multiapp.py +163 -0
  395. mapproxy/test/unit/test_ogr_reader.py +50 -0
  396. mapproxy/test/unit/test_request.py +745 -0
  397. mapproxy/test/unit/test_request_wmts.py +178 -0
  398. mapproxy/test/unit/test_response.py +79 -0
  399. mapproxy/test/unit/test_seed.py +365 -0
  400. mapproxy/test/unit/test_seed_cachelock.py +90 -0
  401. mapproxy/test/unit/test_srs.py +215 -0
  402. mapproxy/test/unit/test_tiled_source.py +122 -0
  403. mapproxy/test/unit/test_tilefilter.py +31 -0
  404. mapproxy/test/unit/test_times.py +25 -0
  405. mapproxy/test/unit/test_timeutils.py +50 -0
  406. mapproxy/test/unit/test_util_conf_utils.py +75 -0
  407. mapproxy/test/unit/test_utils.py +476 -0
  408. mapproxy/test/unit/test_wms_capabilities.py +44 -0
  409. mapproxy/test/unit/test_wms_layer.py +113 -0
  410. mapproxy/test/unit/test_yaml.py +69 -0
  411. mapproxy/tilefilter.py +59 -0
  412. mapproxy/util/__init__.py +0 -0
  413. mapproxy/util/async_.py +227 -0
  414. mapproxy/util/collections.py +132 -0
  415. mapproxy/util/coverage.py +329 -0
  416. mapproxy/util/escape.py +10 -0
  417. mapproxy/util/ext/__init__.py +14 -0
  418. mapproxy/util/ext/dictspec/__init__.py +1 -0
  419. mapproxy/util/ext/dictspec/spec.py +124 -0
  420. mapproxy/util/ext/dictspec/test/__init__.py +0 -0
  421. mapproxy/util/ext/dictspec/test/test_validator.py +274 -0
  422. mapproxy/util/ext/dictspec/validator.py +189 -0
  423. mapproxy/util/ext/local.py +196 -0
  424. mapproxy/util/ext/lockfile.py +138 -0
  425. mapproxy/util/ext/odict.py +330 -0
  426. mapproxy/util/ext/serving.py +508 -0
  427. mapproxy/util/ext/tempita/__init__.py +1174 -0
  428. mapproxy/util/ext/tempita/_looper.py +163 -0
  429. mapproxy/util/ext/tempita/compat3.py +46 -0
  430. mapproxy/util/ext/wmsparse/__init__.py +3 -0
  431. mapproxy/util/ext/wmsparse/duration.py +597 -0
  432. mapproxy/util/ext/wmsparse/parse.py +305 -0
  433. mapproxy/util/ext/wmsparse/test/__init__.py +0 -0
  434. mapproxy/util/ext/wmsparse/test/test_parse.py +162 -0
  435. mapproxy/util/ext/wmsparse/test/test_util.py +23 -0
  436. mapproxy/util/ext/wmsparse/test/wms-large-111.xml +2114 -0
  437. mapproxy/util/ext/wmsparse/test/wms-omniscale-111.xml +90 -0
  438. mapproxy/util/ext/wmsparse/test/wms-omniscale-130.xml +120 -0
  439. mapproxy/util/ext/wmsparse/test/wms_nasa_cap.xml +386 -0
  440. mapproxy/util/ext/wmsparse/util.py +187 -0
  441. mapproxy/util/fs.py +156 -0
  442. mapproxy/util/geom.py +295 -0
  443. mapproxy/util/lib.py +115 -0
  444. mapproxy/util/lock.py +163 -0
  445. mapproxy/util/ogr.py +231 -0
  446. mapproxy/util/py.py +81 -0
  447. mapproxy/util/times.py +75 -0
  448. mapproxy/util/yaml.py +56 -0
  449. mapproxy/version.py +31 -0
  450. mapproxy/wsgiapp.py +164 -0
  451. mapproxy-1.16.1.dist-info/METADATA +151 -0
  452. mapproxy-1.16.1.dist-info/RECORD +458 -0
  453. mapproxy-1.16.1.dist-info/WHEEL +5 -0
  454. mapproxy-1.16.1.dist-info/entry_points.txt +3 -0
  455. mapproxy-1.16.1.dist-info/licenses/AUTHORS.txt +33 -0
  456. mapproxy-1.16.1.dist-info/licenses/COPYING.txt +60 -0
  457. mapproxy-1.16.1.dist-info/licenses/LICENSE.txt +202 -0
  458. mapproxy-1.16.1.dist-info/top_level.txt +1 -0
mapproxy/srs.py ADDED
@@ -0,0 +1,726 @@
1
+ # -*- coding: utf-8 -*-
2
+ # This file is part of the MapProxy project.
3
+ # Copyright (C) 2010 Omniscale <http://omniscale.de>
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ """
18
+ Spatial reference systems and transformation of coordinates.
19
+ """
20
+ from __future__ import division
21
+
22
+ import math
23
+ import threading
24
+ from mapproxy.compat.itertools import izip
25
+ from mapproxy.compat import string_type
26
+ from mapproxy.proj import USE_PROJ4_API
27
+ # Old Proj.4 API
28
+ from mapproxy.proj import Proj, transform, set_datapath
29
+ # New Proj API
30
+ from mapproxy.proj import CRS, Transformer
31
+ from mapproxy.config import base_config
32
+
33
+ import logging
34
+ log_system = logging.getLogger('mapproxy.system')
35
+ log_proj = logging.getLogger('mapproxy.proj')
36
+
37
+ def get_epsg_num(epsg_code):
38
+ """
39
+ >>> get_epsg_num('ePsG:4326')
40
+ 4326
41
+ >>> get_epsg_num(4313)
42
+ 4313
43
+ >>> get_epsg_num('31466')
44
+ 31466
45
+ >>> get_epsg_num('IGNF:ETRS89UTM28') is None
46
+ True
47
+ """
48
+ if isinstance(epsg_code, string_type):
49
+ if ':' in epsg_code and epsg_code.upper().startswith('EPSG'):
50
+ epsg_code = int(epsg_code.split(':')[1])
51
+ elif epsg_code.isdigit():
52
+ epsg_code = int(epsg_code)
53
+ else:
54
+ return
55
+ return epsg_code
56
+
57
+ def get_authority(srs_code):
58
+ """
59
+ >>> get_authority('IAU:1000')
60
+ ('IAU', '1000')
61
+ """
62
+ if isinstance(srs_code, string_type) and ':' in srs_code:
63
+ auth_name, auth_id = srs_code.rsplit(':', 1)
64
+ return auth_name, auth_id
65
+
66
+ def _clean_srs_code(code):
67
+ """
68
+ >>> _clean_srs_code(4326)
69
+ 'EPSG:4326'
70
+ >>> _clean_srs_code('31466')
71
+ 'EPSG:31466'
72
+ >>> _clean_srs_code('crs:84')
73
+ 'CRS:84'
74
+ """
75
+ if isinstance(code, string_type) and ':' in code:
76
+ return code.upper()
77
+ else:
78
+ return 'EPSG:' + str(code)
79
+
80
+ class TransformationError(Exception):
81
+ pass
82
+
83
+ _proj_initialized = False
84
+ def _init_proj():
85
+ global _proj_initialized
86
+ if not _proj_initialized and 'proj_data_dir' in base_config().srs:
87
+ proj_data_dir = base_config().srs['proj_data_dir']
88
+ if proj_data_dir is None:
89
+ _proj_initialized = True
90
+ return
91
+ log_system.info('loading proj data from %s', proj_data_dir)
92
+ set_datapath(proj_data_dir)
93
+ _proj_initialized = True
94
+
95
+ _thread_local = threading.local()
96
+ def SRS(srs_code):
97
+ _init_proj()
98
+ if isinstance(srs_code, _srs_impl):
99
+ return srs_code
100
+
101
+ srs_code = _clean_srs_code(srs_code)
102
+
103
+ if not hasattr(_thread_local, 'srs_cache'):
104
+ _thread_local.srs_cache = {}
105
+
106
+ if srs_code in _thread_local.srs_cache:
107
+ return _thread_local.srs_cache[srs_code]
108
+ else:
109
+ srs = _srs_impl(srs_code)
110
+ _thread_local.srs_cache[srs_code] = srs
111
+ return srs
112
+
113
+ WEBMERCATOR_EPSG = set(('EPSG:900913', 'EPSG:3857',
114
+ 'EPSG:102100', 'EPSG:102113'))
115
+
116
+ class _SRS_Proj4_API(object):
117
+ # http://trac.openlayers.org/wiki/SphericalMercator
118
+ proj_init = {
119
+ 'EPSG:4326': lambda: Proj('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +over'),
120
+ 'CRS:84': lambda: Proj('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +over'),
121
+ }
122
+ for _epsg in WEBMERCATOR_EPSG:
123
+ proj_init[_epsg] = lambda: Proj(
124
+ '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 '
125
+ '+lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m '
126
+ '+nadgrids=@null +no_defs +over')
127
+
128
+ """
129
+ This class represents a Spatial Reference System.
130
+
131
+ Abstracts transformations between different projections.
132
+ Uses the old Proj.4 API, either via pyproj 1 or c-types.
133
+ """
134
+ def __init__(self, srs_code):
135
+ """
136
+ Create a new SRS with the given `srs_code` code.
137
+ """
138
+ self.srs_code = srs_code
139
+
140
+ init = self.proj_init.get(srs_code, None)
141
+ if init is not None:
142
+ self.proj = init()
143
+ else:
144
+ epsg_num = get_epsg_num(srs_code)
145
+ if epsg_num is not None:
146
+ self.proj = Proj(init='epsg:%d' % epsg_num)
147
+ else:
148
+ raise ValueError("the old Proj.4 API doesn't support non-EPSG authorities")
149
+
150
+ def transform_to(self, other_srs, points):
151
+ """
152
+ :type points: ``(x, y)`` or ``[(x1, y1), (x2, y2), …]``
153
+
154
+ >>> srs1 = SRS(4326)
155
+ >>> srs2 = SRS(900913)
156
+ >>> [str(round(x, 5)) for x in srs1.transform_to(srs2, (8.22, 53.15))]
157
+ ['915046.21432', '7010792.20171']
158
+ >>> srs1.transform_to(srs1, (8.25, 53.5))
159
+ (8.25, 53.5)
160
+ >>> [(str(round(x, 5)), str(round(y, 5))) for x, y in
161
+ ... srs1.transform_to(srs2, [(8.2, 53.1), (8.22, 53.15), (8.3, 53.2)])]
162
+ ... #doctest: +NORMALIZE_WHITESPACE
163
+ [('912819.8245', '7001516.67745'),
164
+ ('915046.21432', '7010792.20171'),
165
+ ('923951.77358', '7020078.53264')]
166
+ """
167
+ if self == other_srs:
168
+ return points
169
+ if isinstance(points[0], (int, float)) and 2 >= len(points) <= 3:
170
+ return transform(self.proj, other_srs.proj, *points)
171
+
172
+ x = [p[0] for p in points]
173
+ y = [p[1] for p in points]
174
+ transf_pts = transform(self.proj, other_srs.proj, x, y)
175
+ return izip(transf_pts[0], transf_pts[1])
176
+
177
+ def transform_bbox_to(self, other_srs, bbox, with_points=16):
178
+ """
179
+
180
+ :param with_points: the number of points to use for the transformation.
181
+ A bbox transformation with only two or four points may cut off some
182
+ parts due to distortions.
183
+
184
+ >>> ['%.3f' % x for x in
185
+ ... SRS(4326).transform_bbox_to(SRS(3857), (-180.0, -90.0, 180.0, 90.0))]
186
+ ['-20037508.343', '-147730762.670', '20037508.343', '147730758.195']
187
+ >>> ['%.5f' % x for x in
188
+ ... SRS(4326).transform_bbox_to(SRS(3857), (8.2, 53.1, 8.3, 53.2))]
189
+ ['912819.82450', '7001516.67745', '923951.77358', '7020078.53264']
190
+ >>> SRS(4326).transform_bbox_to(SRS(4326), (8.25, 53.0, 8.5, 53.75))
191
+ (8.25, 53.0, 8.5, 53.75)
192
+ """
193
+ if self == other_srs:
194
+ return bbox
195
+ bbox = self.align_bbox(bbox)
196
+ points = generate_envelope_points(bbox, with_points)
197
+ transf_pts = self.transform_to(other_srs, points)
198
+ result = calculate_bbox(transf_pts)
199
+
200
+ log_proj.debug('transformed from %r to %r (%s -> %s)',
201
+ self, other_srs, bbox, result)
202
+
203
+ return result
204
+
205
+ def align_bbox(self, bbox):
206
+ """
207
+ Align bbox to reasonable values to prevent errors in transformations.
208
+ E.g. transformations from EPSG:4326 with lat=90 or -90 will fail, so
209
+ we subtract a tiny delta.
210
+
211
+ At the moment only EPSG:4326 bbox will be modifyed.
212
+
213
+ >>> bbox = SRS(4326).align_bbox((-180, -90, 180, 90))
214
+ >>> -90 < bbox[1] < -89.99999998
215
+ True
216
+ >>> 90 > bbox[3] > 89.99999998
217
+ True
218
+ """
219
+ # TODO should not be needed anymore since we transform with +over
220
+ # still a few tests depend on the rounding behavior of this
221
+ if self.srs_code == 'EPSG:4326':
222
+ delta = 0.00000001
223
+ (minx, miny, maxx, maxy) = bbox
224
+ if abs(miny - -90.0) < 1e-6:
225
+ miny = -90.0 + delta
226
+ if abs(maxy - 90.0) < 1e-6:
227
+ maxy = 90.0 - delta
228
+ bbox = minx, miny, maxx, maxy
229
+ return bbox
230
+
231
+ @property
232
+ def is_latlong(self):
233
+ """
234
+ >>> SRS(4326).is_latlong
235
+ True
236
+ >>> SRS(31466).is_latlong
237
+ False
238
+ """
239
+ return self.proj.is_latlong()
240
+
241
+
242
+ def get_geographic_srs(self):
243
+ """ Return the "canonical" geographic CRS corresponding to this CRS.
244
+ Always EPSG:4326 for Proj4 implementation """
245
+ return SRS(4326)
246
+
247
+
248
+ @property
249
+ def is_axis_order_ne(self):
250
+ """
251
+ Returns `True` if the axis order is North, then East
252
+ (i.e. y/x or lat/lon).
253
+
254
+ >>> SRS(4326).is_axis_order_ne
255
+ True
256
+ >>> SRS('CRS:84').is_axis_order_ne
257
+ False
258
+ >>> SRS(31468).is_axis_order_ne
259
+ True
260
+ >>> SRS(31463).is_axis_order_ne
261
+ False
262
+ >>> SRS(25831).is_axis_order_ne
263
+ False
264
+ """
265
+ if self.srs_code in base_config().srs.axis_order_ne:
266
+ return True
267
+ if self.srs_code in base_config().srs.axis_order_en:
268
+ return False
269
+ if self.is_latlong:
270
+ return True
271
+ return False
272
+
273
+ @property
274
+ def is_axis_order_en(self):
275
+ """
276
+ Returns `True` if the axis order is East then North
277
+ (i.e. x/y or lon/lat).
278
+ """
279
+ return not self.is_axis_order_ne
280
+
281
+ def __eq__(self, other):
282
+ """
283
+ >>> SRS(4326) == SRS("EpsG:4326")
284
+ True
285
+ >>> SRS(4326) == SRS("4326")
286
+ True
287
+ >>> SRS(4326) == SRS(3857)
288
+ False
289
+ """
290
+ if isinstance(other, _SRS_Proj4_API):
291
+ return self.proj.srs == other.proj.srs
292
+ else:
293
+ return NotImplemented
294
+
295
+ def __ne__(self, other):
296
+ """
297
+ >>> SRS(3857) != SRS(3857)
298
+ False
299
+ >>> SRS(4326) != SRS(900913)
300
+ True
301
+ """
302
+ equal_result = self.__eq__(other)
303
+ if equal_result is NotImplemented:
304
+ return NotImplemented
305
+ else:
306
+ return not equal_result
307
+
308
+ def __str__(self):
309
+ #pylint: disable-msg=E1101
310
+ return "SRS %s ('%s')" % (self.srs_code, self.proj.srs)
311
+
312
+ def __repr__(self):
313
+ """
314
+ >>> repr(SRS(4326))
315
+ "SRS('EPSG:4326')"
316
+ """
317
+ return "SRS('%s')" % (self.srs_code,)
318
+
319
+ def __hash__(self):
320
+ return hash(self.srs_code)
321
+
322
+
323
+ class _SRS(object):
324
+ """
325
+ This class represents a Spatial Reference System.
326
+
327
+ Abstracts transformations between different projections.
328
+ Uses the new Proj API via pyproj >=2.
329
+ """
330
+ def __init__(self, srs_code):
331
+ """
332
+ Create a new SRS with the given `srs_code` code.
333
+ """
334
+ self.srs_code = srs_code
335
+
336
+ if srs_code in WEBMERCATOR_EPSG:
337
+ epsg_num = 3857
338
+ elif srs_code == 'CRS:84':
339
+ epsg_num = 4326
340
+ else:
341
+ epsg_num = get_epsg_num(srs_code)
342
+
343
+ if epsg_num is not None:
344
+ self.proj = CRS.from_epsg(epsg_num)
345
+ else:
346
+ auth_name, auth_id = get_authority(srs_code)
347
+ self.proj = CRS.from_authority(auth_name, auth_id)
348
+
349
+ self._transformers = {}
350
+
351
+ def _transformer(self, other_srs):
352
+ if other_srs in self._transformers:
353
+ return self._transformers[other_srs]
354
+
355
+ t = Transformer.from_crs(self.proj, other_srs.proj, always_xy=True)
356
+ self._transformers[other_srs] = t
357
+ return t
358
+
359
+ def transform_to(self, other_srs, points):
360
+ """
361
+ :type points: ``(x, y)`` or ``[(x1, y1), (x2, y2), …]``
362
+
363
+ >>> srs1 = SRS(4326)
364
+ >>> srs2 = SRS(900913)
365
+ >>> [str(round(x, 5)) for x in srs1.transform_to(srs2, (8.22, 53.15))]
366
+ ['915046.21432', '7010792.20171']
367
+ >>> srs1.transform_to(srs1, (8.25, 53.5))
368
+ (8.25, 53.5)
369
+ >>> [(str(round(x, 5)), str(round(y, 5))) for x, y in
370
+ ... srs1.transform_to(srs2, [(8.2, 53.1), (8.22, 53.15), (8.3, 53.2)])]
371
+ ... #doctest: +NORMALIZE_WHITESPACE
372
+ [('912819.8245', '7001516.67745'),
373
+ ('915046.21432', '7010792.20171'),
374
+ ('923951.77358', '7020078.53264')]
375
+ """
376
+ if self == other_srs:
377
+ return points
378
+
379
+
380
+ transformer = self._transformer(other_srs)
381
+ if isinstance(points[0], (int, float)) and 2 >= len(points) <= 3:
382
+ return transformer.transform(*points)
383
+
384
+ x = [p[0] for p in points]
385
+ y = [p[1] for p in points]
386
+ transf_pts = transformer.transform(x, y)
387
+ return izip(transf_pts[0], transf_pts[1])
388
+
389
+ def transform_bbox_to(self, other_srs, bbox, with_points=16):
390
+ """
391
+
392
+ :param with_points: the number of points to use for the transformation.
393
+ A bbox transformation with only two or four points may cut off some
394
+ parts due to distortions.
395
+
396
+ >>> ['%.3f' % x for x in
397
+ ... SRS(4326).transform_bbox_to(SRS(3857), (-180.0, -90.0, 180.0, 90.0))]
398
+ ['-20037508.343', '-20037508.343', '20037508.343', '20037508.343']
399
+ >>> ['%.5f' % x for x in
400
+ ... SRS(4326).transform_bbox_to(SRS(3857), (8.2, 53.1, 8.3, 53.2))]
401
+ ['912819.82450', '7001516.67745', '923951.77358', '7020078.53264']
402
+ >>> SRS(4326).transform_bbox_to(SRS(4326), (8.25, 53.0, 8.5, 53.75))
403
+ (8.25, 53.0, 8.5, 53.75)
404
+ """
405
+ if self == other_srs:
406
+ return bbox
407
+ bbox = bbox
408
+ points = generate_envelope_points(bbox, with_points)
409
+ transf_pts = list(self.transform_to(other_srs, points))
410
+ result = calculate_bbox(transf_pts)
411
+
412
+ log_proj.debug('transformed from %r to %r (%s -> %s)',
413
+ self, other_srs, bbox, result)
414
+
415
+ # XXX: 3857 is only defined within 85.06 N/S, new Proj returns 'inf' for coords
416
+ # outside of these bounds. Adjust bbox for 4326->3857 transformations to the old
417
+ # behavior, as this is expected in a few places (WMS layer extents and quite a few
418
+ # tests).
419
+ if self.srs_code == 'EPSG:4326' and other_srs.srs_code in ('EPSG:3857', 'EPSG:900913'):
420
+ minx, miny, maxx, maxy = result
421
+ if bbox[0] <= -180.0:
422
+ minx = -20037508.342789244
423
+ if bbox[1] <= -85.06:
424
+ miny = -20037508.342789244
425
+ if bbox[2] >= 180.0:
426
+ maxx = 20037508.342789244
427
+ if bbox[3] >= 85.06:
428
+ maxy = 20037508.342789244
429
+ result = (minx, miny, maxx, maxy)
430
+ return result
431
+
432
+ @property
433
+ def is_latlong(self):
434
+ """
435
+ >>> SRS(4326).is_latlong
436
+ True
437
+ >>> SRS(31466).is_latlong
438
+ False
439
+ """
440
+ return self.proj.is_geographic
441
+
442
+
443
+ def get_geographic_srs(self):
444
+ """ Return the "canonical" geographic CRS corresponding to this CRS.
445
+ EPSG:4326 for Earth CRS, or another one from other celestial bodies """
446
+ auth = self.proj.to_authority()
447
+ if auth is None or not auth[0].startswith('IAU'):
448
+ ret = SRS(4326)
449
+ else:
450
+ return _SRS(':'.join(self.proj.geodetic_crs.to_authority()))
451
+ return ret
452
+
453
+ @property
454
+ def is_axis_order_ne(self):
455
+ """
456
+ Returns `True` if the axis order is North, then East
457
+ (i.e. y/x or lat/lon).
458
+
459
+ >>> SRS(4326).is_axis_order_ne
460
+ True
461
+ >>> SRS('CRS:84').is_axis_order_ne
462
+ False
463
+ >>> SRS(31468).is_axis_order_ne
464
+ True
465
+ >>> SRS(31463).is_axis_order_ne
466
+ False
467
+ >>> SRS(25831).is_axis_order_ne
468
+ False
469
+ """
470
+ if self.srs_code == 'CRS:84':
471
+ return False
472
+ return self.proj.axis_info[0].direction == 'north'
473
+
474
+ @property
475
+ def is_axis_order_en(self):
476
+ """
477
+ Returns `True` if the axis order is East then North
478
+ (i.e. x/y or lon/lat).
479
+ """
480
+ return not self.is_axis_order_ne
481
+
482
+
483
+ def align_bbox(self, bbox):
484
+ """
485
+ Align bbox to reasonable values to prevent errors in transformations.
486
+ E.g. transformations from EPSG:4326 with lat=90 or -90 will fail, so
487
+ we subtract a tiny delta.
488
+
489
+ At the moment only EPSG:4326 bbox will be modifyed.
490
+
491
+ >>> bbox = SRS(4326).align_bbox((-180, -90, 180, 90))
492
+ >>> -90 < bbox[1] < -89.99999998
493
+ True
494
+ >>> 90 > bbox[3] > 89.99999998
495
+ True
496
+ """
497
+ # TODO should not be needed anymore since we transform with +over
498
+ # still a few tests depend on the rounding behavior of this
499
+ if self.srs_code == 'EPSG:4326':
500
+ delta = 0.00000001
501
+ (minx, miny, maxx, maxy) = bbox
502
+ if abs(miny - -90.0) < 1e-6:
503
+ miny = -90.0 + delta
504
+ if abs(maxy - 90.0) < 1e-6:
505
+ maxy = 90.0 - delta
506
+ bbox = minx, miny, maxx, maxy
507
+ return bbox
508
+
509
+ def __eq__(self, other):
510
+ """
511
+ >>> SRS(4326) == SRS("EpsG:4326")
512
+ True
513
+ >>> SRS(4326) == SRS("4326")
514
+ True
515
+ >>> SRS(4326) == SRS(3857)
516
+ False
517
+ """
518
+ if isinstance(other, _SRS):
519
+ return self.proj.srs == other.proj.srs
520
+ else:
521
+ return NotImplemented
522
+
523
+ def __ne__(self, other):
524
+ """
525
+ >>> SRS(3857) != SRS(3857)
526
+ False
527
+ >>> SRS(4326) != SRS(900913)
528
+ True
529
+ """
530
+ equal_result = self.__eq__(other)
531
+ if equal_result is NotImplemented:
532
+ return NotImplemented
533
+ else:
534
+ return not equal_result
535
+
536
+ def __str__(self):
537
+ #pylint: disable-msg=E1101
538
+ return "SRS %s ('%s')" % (self.srs_code, self.proj.srs)
539
+
540
+ def __repr__(self):
541
+ """
542
+ >>> repr(SRS(4326))
543
+ "SRS('EPSG:4326')"
544
+ """
545
+ return "SRS('%s')" % (self.srs_code,)
546
+
547
+ def __hash__(self):
548
+ return hash(self.srs_code)
549
+
550
+
551
+ if USE_PROJ4_API:
552
+ _srs_impl = _SRS_Proj4_API
553
+ del _SRS
554
+ else:
555
+ _srs_impl = _SRS
556
+ del _SRS_Proj4_API
557
+
558
+
559
+
560
+ def generate_envelope_points(bbox, n):
561
+ """
562
+ Generates points that form a linestring around a given bbox.
563
+
564
+ @param bbox: bbox to generate linestring for
565
+ @param n: the number of points to generate around the bbox
566
+
567
+ >>> generate_envelope_points((10.0, 5.0, 20.0, 15.0), 4)
568
+ [(10.0, 5.0), (20.0, 5.0), (20.0, 15.0), (10.0, 15.0)]
569
+ >>> generate_envelope_points((10.0, 5.0, 20.0, 15.0), 8)
570
+ ... #doctest: +NORMALIZE_WHITESPACE
571
+ [(10.0, 5.0), (15.0, 5.0), (20.0, 5.0), (20.0, 10.0),\
572
+ (20.0, 15.0), (15.0, 15.0), (10.0, 15.0), (10.0, 10.0)]
573
+ """
574
+ (minx, miny, maxx, maxy) = bbox
575
+ if n <= 4:
576
+ n = 0
577
+ else:
578
+ n = int(math.ceil((n - 4) / 4.0))
579
+
580
+ width = maxx - minx
581
+ height = maxy - miny
582
+
583
+ minx, maxx = min(minx, maxx), max(minx, maxx)
584
+ miny, maxy = min(miny, maxy), max(miny, maxy)
585
+
586
+ n += 1
587
+ xstep = width / n
588
+ ystep = height / n
589
+ result = []
590
+ for i in range(n+1):
591
+ result.append((minx + i*xstep, miny))
592
+ for i in range(1, n):
593
+ result.append((maxx, miny + i*ystep))
594
+ for i in range(n, -1, -1):
595
+ result.append((minx + i*xstep, maxy))
596
+ for i in range(n-1, 0, -1):
597
+ result.append((minx, miny + i*ystep))
598
+ return result
599
+
600
+ def calculate_bbox(points):
601
+ """
602
+ Calculates the bbox of a list of points.
603
+
604
+ >>> calculate_bbox([(-5, 20), (3, 8), (99, 0)])
605
+ (-5, 0, 99, 20)
606
+
607
+ @param points: list of points [(x0, y0), (x1, y2), ...]
608
+ @returns: bbox of the input points.
609
+ """
610
+ points = list(points)
611
+ # points can be INF for invalid transformations, filter out
612
+ try:
613
+ minx = min(p[0] for p in points if p[0] != float('inf'))
614
+ miny = min(p[1] for p in points if p[1] != float('inf'))
615
+ maxx = max(p[0] for p in points if p[0] != float('inf'))
616
+ maxy = max(p[1] for p in points if p[1] != float('inf'))
617
+ return (minx, miny, maxx, maxy)
618
+ except ValueError: # min/max are called with empty list when everything is inf
619
+ raise TransformationError()
620
+
621
+ def merge_bbox(bbox1, bbox2):
622
+ """
623
+ Merge two bboxes.
624
+
625
+ >>> merge_bbox((-10, 20, 0, 30), (30, -20, 90, 10))
626
+ (-10, -20, 90, 30)
627
+
628
+ """
629
+ minx = min(bbox1[0], bbox2[0])
630
+ miny = min(bbox1[1], bbox2[1])
631
+ maxx = max(bbox1[2], bbox2[2])
632
+ maxy = max(bbox1[3], bbox2[3])
633
+ return (minx, miny, maxx, maxy)
634
+
635
+
636
+ def bbox_equals(src_bbox, dst_bbox, x_delta=None, y_delta=None):
637
+ """
638
+ Compares two bbox and checks if they are equal, or nearly equal.
639
+
640
+ :param x_delta: how precise the comparison should be.
641
+ should be reasonable small, like a tenth of a pixel.
642
+ defaults to 1/1.000.000th of the width.
643
+ :type x_delta: bbox units
644
+
645
+ >>> src_bbox = (939258.20356824622, 6887893.4928338043,
646
+ ... 1095801.2374962866, 7044436.5267618448)
647
+ >>> dst_bbox = (939258.20260000182, 6887893.4908000007,
648
+ ... 1095801.2365000017, 7044436.5247000009)
649
+ >>> bbox_equals(src_bbox, dst_bbox, 61.1, 61.1)
650
+ True
651
+ >>> bbox_equals(src_bbox, dst_bbox, 0.0001)
652
+ False
653
+ """
654
+ if x_delta is None:
655
+ x_delta = abs(src_bbox[0] - src_bbox[2]) / 1000000.0
656
+ if y_delta is None:
657
+ y_delta = x_delta
658
+ return (abs(src_bbox[0] - dst_bbox[0]) < x_delta and
659
+ abs(src_bbox[1] - dst_bbox[1]) < x_delta and
660
+ abs(src_bbox[2] - dst_bbox[2]) < y_delta and
661
+ abs(src_bbox[3] - dst_bbox[3]) < y_delta)
662
+
663
+ def make_lin_transf(src_bbox, dst_bbox):
664
+ """
665
+ Create a transformation function that transforms linear between two
666
+ plane coordinate systems.
667
+ One needs to be cartesian (0, 0 at the lower left, x goes up) and one
668
+ needs to be an image coordinate system (0, 0 at the top left, x goes down).
669
+
670
+ :return: function that takes src x/y and returns dest x/y coordinates
671
+
672
+ >>> transf = make_lin_transf((7, 50, 8, 51), (0, 0, 500, 400))
673
+ >>> transf((7.5, 50.5))
674
+ (250.0, 200.0)
675
+ >>> transf((7.0, 50.0))
676
+ (0.0, 400.0)
677
+ >>> transf = make_lin_transf((7, 50, 8, 51), (200, 300, 700, 700))
678
+ >>> transf((7.5, 50.5))
679
+ (450.0, 500.0)
680
+ """
681
+ func = lambda x_y: (dst_bbox[0] + (x_y[0] - src_bbox[0]) *
682
+ (dst_bbox[2]-dst_bbox[0]) / (src_bbox[2] - src_bbox[0]),
683
+ dst_bbox[1] + (src_bbox[3] - x_y[1]) *
684
+ (dst_bbox[3]-dst_bbox[1]) / (src_bbox[3] - src_bbox[1]))
685
+ return func
686
+
687
+
688
+ class PreferredSrcSRS(object):
689
+ def __init__(self):
690
+ self.target_proj = {}
691
+
692
+ def add(self, target, prefered_srs):
693
+ self.target_proj[target] = prefered_srs
694
+
695
+ def preferred_src(self, target, available_src):
696
+ if not available_src:
697
+ raise ValueError("no available src SRS")
698
+ if target in available_src:
699
+ return target
700
+ if target in self.target_proj:
701
+ for preferred in self.target_proj[target]:
702
+ if preferred in available_src:
703
+ return preferred
704
+
705
+ for avail in available_src:
706
+ if avail.is_latlong == target.is_latlong:
707
+ return avail
708
+ return available_src[0]
709
+
710
+ class SupportedSRS(object):
711
+ def __init__(self, supported_srs, preferred_srs=None):
712
+ self.supported_srs = supported_srs
713
+ self.preferred_srs = preferred_srs or PreferredSrcSRS()
714
+
715
+ def __iter__(self):
716
+ return iter(self.supported_srs)
717
+
718
+ def __contains__(self, srs):
719
+ return srs in self.supported_srs
720
+
721
+ def best_srs(self, target):
722
+ return self.preferred_srs.preferred_src(target, self.supported_srs)
723
+
724
+ def __eq__(self, other):
725
+ # .prefered_srs is set global, so we only compare .supported_srs
726
+ return self.supported_srs == other.supported_srs